创建一个通用方法来处理Collection Java以改变ArrayList

时间:2017-12-14 17:44:31

标签: java generics arraylist

我想创建一个泛型方法,它可以采用Integer,Float的ArrayList或任何扩展Number的类型。

public void mulBy2(ArrayList<? extends Number> list) {
// I want to multiply the value of each element in list by 2
// and store it back in list
for(int i = 0; i < al.size(); i++) {
  Double d =  al.get(i).doubleValue()*2;
  al.set(i,d); // Obvious error here says required ? extends Number
// how to solve this issue
}
}

如果list是值为[2,3,4]的ArrayList,我的方法应该返回或者使用值为[4,6,8]的arrayList 最初[1.2,3.4]的ArrayList应转换为[2.4,6.8]

2 个答案:

答案 0 :(得分:1)

我们不想做你的作业,但我认为这个问题应该回答,因为它对未来的访问者有用。解决方案应包括以下内容:

  • 迭代元素
  • 获取当前元素的class
  • 将相应的方法调用到当前元素的class以获取其值,如果它是Integerinvoke通过反射对象的intValue,将其乘以2并将列表的相应元素设置为新值

有用的知道:

  1. 相应的方法有:intValuelongValuefloatValuedoubleValuebyteValueshortValue,与DoubleFloat等相关的类或多或少与它们相关联。请参阅此处:https://docs.oracle.com/javase/7/docs/api/java/lang/Number.html

  2. 您可以通过调用class方法获取Object的{​​{1}}。可以通过调用生成的getClass的getEnclosingClass来获取其名称。例如:

  3. class

    1. 使用反射,您可以调用invoke来调用方法。例如:
    2. Class<?> enclosingClass = getClass().getEnclosingClass(); if (enclosingClass != null) { System.out.println(enclosingClass.getName()); } else { System.out.println(getClass().getName()); }

      祝你好运!

答案 1 :(得分:0)

1。填充了Double-s

<Number>列表

这是一个快速修复:

public void mulBy2(List<Number> list) {
    for (int i = 0; i < list.size(); i++) {
      Double d =  list.get(i).doubleValue()*2;
      list.set(i,d);
    }
}

该修复程序包含以下更改:

  1. 完全可以期待List<Number>List<Number>可以保留任何数字组合,例如IntegerFloatBigDecimal
  2. 最好对接口进行编码,例如: List而不是实施,ArrayList
  3. 现在我们只需添加Double个数字。
  4. 此代码存在一些问题:

    1. 所有加倍的数字都是双打。
    2. 您不能再传递List<Integer>参数。
    3. 此方法无法处理具有较大值的BigDecimal -s
    4. 2。带insanceof的绑定子类型检查。

      所以让我们写另一个修复:

      public <T extends Number> void mulBy2Attempt2(List<T> list) {
          for (int i = 0; i < list.size(); i++) {
              list.set(i, multiplyBy2(list.get(i)));
          }
      }
      
      private <T extends Number> T multiplyBy2(T num) {
          if (num instanceof BigDecimal) {
              return (T) ((BigDecimal) num).multiply(new BigDecimal(2));
          }
          if (num instanceof BigInteger) {
              return (T) ((BigInteger) num).multiply(new BigInteger("2"));
          }
          if (num instanceof Long) {
              return (T) new Long(num.longValue() * 2);
          }
          if (num instanceof Integer) {
              return (T) new Integer(num.intValue() * 2);
          }
          if ((num instanceof Double)) {
              return (T) new Double(num.doubleValue() * 2);
          }
          if (num instanceof Float) {
              return (T) new Float(num.floatValue() * 2);
          }
          if (num instanceof Byte) {
              return (T) new Byte((byte) (num.byteValue() * 2));
          }
          if (num == null) {
              throw new NullPointerException("Cannot multiply a null-number by two");
          }
          throw new IllegalArgumentException("Cannot handle a number of " + num.getClass().getCanonicalName() + " yet.");
      }
      

      这真的很酷。由于绑定类型<T extends Number>,它可以接受任何类型的列表,例如List<AtomicInteger>List<Number>。这个解决方案有一些缺点:

      1. 它严重依赖于instanceof支票
      2. 它不可能处理所有Number子类,因为任何人都可以自由地实现新的Number子类,然后你就完成了。
      3. 3。让调用者决定如何乘以2

        我们可以使用lambdas将这个负担放在调用者身上:

        public <T extends Number> void mulBy2Attempt3(List<T> list, Function<T,T> multiplier) {
            for (int i = 0; i < list.size(); i++) {
                list.set(i, multiplier.apply(list.get(i)));
            }
        }
        

        所以你可以这样称呼它:

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        mulBy2Attempt3(list, n -> n * 2);
        System.out.println(list);
        

        4。使用Streams和map

        我们现在拥有的几乎就像map函数:

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        
        List<Integer> list2 = list.stream().map(n -> n * 2).collect(Collectors.toList());
            System.out.println(list2);
        

        这略有不同,因为它不会修改原始列表。

        现在你有几种选择。根据您的要求,您可以决定走哪条路。