Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何对列表的每个元素执行操作并返回结果(当然不会影响原始结果)?_Java_List_Generics - Fatal编程技术网

Java 如何对列表的每个元素执行操作并返回结果(当然不会影响原始结果)?

Java 如何对列表的每个元素执行操作并返回结果(当然不会影响原始结果)?,java,list,generics,Java,List,Generics,我如何用Java编写一个静态方法,它将获取一个列表,对每个元素执行一个操作,并返回结果(当然不会影响原始结果) 例如,如果我想在每个元素中添加2,那么。。。在这里具体返回类型必须相同,例如,如果我的列表是一个值为1,2,3的LinkedList,我应该返回一个值为3,4,5的LinkedList。类似地,ArrayList、Vector、Stack等都是列表 我可以看到如何使用多个if(LinkedList的lst instanceof)来实现这一点。等等。。。还有更好的办法吗 import j

我如何用Java编写一个静态方法,它将获取一个列表,对每个元素执行一个操作,并返回结果(当然不会影响原始结果)

例如,如果我想在每个元素中添加2,那么。。。在这里具体返回类型必须相同,例如,如果我的列表是一个值为1,2,3的LinkedList,我应该返回一个值为3,4,5的LinkedList。类似地,ArrayList、Vector、Stack等都是列表

我可以看到如何使用多个
if(LinkedList的lst instanceof)来实现这一点。
等等。。。还有更好的办法吗

import java.util.List;

public class ListAdd {       

    static List<Integer> add2 (List<Integer> lst) {

    ...

        return result;
    }
}
import java.util.List;
公共类ListAdd{
静态列表add2(列表lst){
...
返回结果;
}
}

基本上,
列表
界面不能保证您有办法复制它

您可能会在各种技巧上获得一些运气:

  • 在传入的
    列表上使用
    clone()
    ,尽管它可能抛出,或者(因为它在
    对象中受保护)根本无法访问
  • 使用反射在传入的
    列表中查找公共无参数构造函数
  • 尝试序列化和反序列化以执行“深度克隆”
  • 创建某种工厂并内置如何复制代码可能遇到的每种不同类型的列表的知识(如果它是由
    unmodifiableList()
    创建的包装器,或者是由
    RandomAccessFile
    支持的一些奇怪的自定义实现,该怎么办?)
  • 如果所有其他操作都失败,请抛出或返回
    ArrayList
    Vector
    ,因为缺少更好的选项

    • 在本例中,使用接口的全部目的是抽象出一个事实,即实现隐藏在接口后面

      但是,我很清楚您的意图:
      Clonable
      接口支持创建具有相同状态的新实例。您的
      列表中可能未定义此接口

      通常,重新思考这种情况是一个好主意:为什么需要在这个地方,这个类中克隆
      列表?你的列表创建者不应该负责克隆列表吗?或者,知道类型的来电者不应该确保他传递了他的列表的克隆吗

      也许,如果您按照定义的语义查找,您可以实现所有受支持的
      列表
      s:

      static Vector<Integer> addTwo(Vector<Integer> vector) {
          Vector<Integer> copy = null; // TODO: copy the vector
          return addTwo_mutable(copy);
      }
      static ArrayList<Integer> addTwo(ArrayList<Integer> aList) {
          ArrayList<Integer> copy = null; // TODO: copy the array list
          return addTwo_mutable(copy);
      }
      static LinkedList<Integer> addTwo(LinkedList<Integer> lList) {
          LinkedList<Integer> copy = null; // TODO: copy the linked list
          return addTwo_mutable(copy);
      }
      
      private <T extends List<Integer>> static T addTwo_mutable(T list) {
          return list; // TODO: implement
      }
      
      静态向量addTwo(向量向量){
      Vector copy=null;//TODO:复制向量
      返回addTwo_可变(副本);
      }
      静态ArrayList addTwo(ArrayList列表){
      ArrayList copy=null;//TODO:复制数组列表
      返回addTwo_可变(副本);
      }
      静态LinkedList addTwo(LinkedList lList){
      LinkedList copy=null;//TODO:复制链接列表
      返回addTwo_可变(副本);
      }
      私有静态T addTwo_可变(T列表){
      返回列表;//TODO:实现
      }
      
      甚至,当您不支持数据类型时,也会出现一个很好的编译器错误,即指定的方法不存在


      (代码未测试)

      您可以使用反射在lst.getClass()的结果上查找公共零参数构造函数,然后调用它()以获得将结果放入其中的列表。Java集合框架建议集合的任何派生都提供零参数构造函数。这样,您的结果将与参数属于同一运行时类。

      这里有一个变量,它既不复制也不修改原始列表。相反,它用另一个对象包装原始列表

      public List<Integer> add2(final List<Integer> lst) {
          return new AbstractList<Integer>() {
              public int size() {
                  return lst.size();
              }
              public Integer get(int index) {
                  return 2 + lst.get(index);
              }
          };
      }
      
      public List add2(最终列表lst){
      返回新的AbstractList(){
      公共整数大小(){
      返回lst.size();
      }
      公共整数get(整数索引){
      返回2+1.get(索引);
      }
      };
      }
      
      返回的列表不可修改,但会在原始列表更改时更改。 (这实现了基于索引访问的迭代器,因此对于链表来说速度较慢。然后最好基于AbstractSequentialList实现它。)

      当然,生成的列表显然与原始列表不属于同一类


      仅当您确实只需要原始列表的只读两个添加视图时,才使用此解决方案,而不需要具有类似属性的修改副本。

      好的,有人提到了反射。这似乎是一个优雅的解决方案:

      import java.util.*;
      public class ListAdd {
      
          static List<Integer> add2 (List<Integer> lst) throws Exception {
      
              List<Integer> result = lst.getClass().newInstance();
              for (Integer i : lst) result.add(i + 2);
      
              return result;
          }
      }
      
      我认为,如果传入一个没有空构造函数的列表,抛出运行时异常是最糟糕的选择。我看不出有什么办法可以确保它做到这一点。(Java 8类型的注释是否可以拯救?)返回
      null
      会有点无用

      使用此签名的缺点是,我们不能将
      ArrayList
      等作为默认值返回,因为我们可以将其作为引发异常的替代方法,因为返回类型保证与传入的类型相同。但是,如果用户确实想要返回ArrayList(或其他默认类型),则可以创建ArrayList副本并在该副本上使用该方法


      如果有API设计经验的人读过这篇文章,我很想知道您对哪个选项更可取的想法:1)返回需要显式转换回原始类型的列表,但允许返回不同的具体类型,或2)确保返回类型相同(使用泛型),但是,如果(例如)传入一个没有空构造函数的单例对象,则可能会出现异常?

      已经有很多答案,但我想向您展示一种不同的方法来思考这个问题

      在函数式编程中,您要执行的操作称为
      map
      。这是我们在函数式语言中一直在做的事情

      M
      成为某种容器(在您的情况下,
      Mstatic <T extends List<Integer>> T add2 (T lst) {
          T res;
          try {
              res = (T) lst.getClass().newInstance();
      
          } catch (InstantiationException e) {
              throw new IllegalArgumentException(e);
          } catch (IllegalAccessException e) {
              throw new RuntimeException(e);
          }
      
          for (Integer i : lst) res.add(i + 2);
          return res;
      }    
      
      M<B> map(M<A>, F<A, B>)
      
      static List<Integer> add2(List<Integer> ns) {
        return Lists.transform(ns, new Function<Integer, Integer>() {
          @Override Integer apply(Integer n) { return n + 2; }
        }
      }
      
      final class MyList extends ArrayList<Integer> {
        private MyList() {
          super.add(1);
          super.add(2);
          super.add(3);
        }
        private static class SingletonHolder {
          private static final MyList instance = new MyList();
        }
        public static MyList getInstance() {
          return SingletonHolder.instance;
        }
      }