【问题标题】:Is it possible to convert the return type of collect (Collectors.ToList() to LinkedList?是否可以将 collect (Collectors.ToList() 的返回类型转换为 LinkedList?
【发布时间】:2021-09-25 08:28:39
【问题描述】:

我想写一个函数来创建一个随机数流:

import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

public class fillRandom {
    public static List<Integer> IntFill(){
        return  new Random().ints(10,0,100).boxed().collect(Collectors.toList());

    }
}

然后我想将它返回到我的 LinkedList:

public class Main {

    public static void main(String[] args) throws Exception {
        List linkedList = new LinkedList<Integer>();
        Print printer = new printImpl();
        linkedList = (LinkedList) fillRandom.IntFill();
        printer.print(linkedList);

    }

}

但我收到一个错误Exception in thread "main" java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.util.LinkedList

如果没有collect(Collectors.toCollection(LinkedList::new)),是否可以做一些事情让它工作?如果我不想从 Random 中准确返回 ArrayList

【问题讨论】:

  • 你为什么不想使用toCollection?它有什么问题?
  • @Sweeper 好吧,我只是认为最好不要依赖一种实现,而是分配我拥有的一个(LinkedList 或 ArrayList)
  • List&lt;Integer&gt; list = fillRandom.IntFill(); List&lt;Integer&gt; lL = new LinkedList&lt;&gt;(list);
  • 为什么要LinkedList?就性能和内存开销而言,这几乎总是错误的选择。
  • 您提到“分配我拥有的那个”,但是您将其分配给列表。您将其声明为 List linkedlist 而不是 LinkedList linkedlist。您使用 new LinkedList&lt;Integer&gt;() 创建的第一个 LinkedList 被完全丢弃,并在您将其分配给 linkedList = (LinkedList) fillRandom.IntFill() 中的新链接后立即收集垃圾。

标签: java stream


【解决方案1】:

根据toList的文档,不能保证返回的列表类型,特地请你使用toCollection

不保证返回的 List 的类型、可变性、可序列化性或线程安全性;如果需要对返回的 List 进行更多控制,请使用 toCollection(Supplier)

如果您不使用toCollection 的原因仅仅是为了避免使用intFill 中的特定实现,并希望允许调用者指定他们想要的List,您总是可以为用户提供该选项Supplier 参数,就像 toCollection 所做的那样。

public static <C extends Collection<Integer>> C intFill(Supplier<C> collectionSupplier){
    return new Random().ints(10,0,100).boxed()
        .collect(Collectors.toCollection(collectionSupplier));
}

用法:

List<Integer> linkedList = fillRandom.intFill(LinkedList::new);

或者,使用LinkedList 构造函数从toList 收集器返回的任何List 创建一个LinkedList,而不是强制转换。

List<Integer> linkedList = new LinkedList<>(fillRandom.intFill());

请注意,这样做的一个缺点是它会再次循环整个列表,这可能是不可取的。

【讨论】:

    【解决方案2】:

    您应该坚持使用接口List,而不是使用实现类LinkedList

    话虽如此,如果你真的想收集到你已经拥有的对象的类,你可以通过首先让收集器知道你想要基于什么对象来做这样的事情(虽然我不推荐它):

    import java.util.List;
    import java.util.Random;
    import java.util.stream.Collectors;
    
    public class fillRandom {
        public static List<Integer> IntFill(List base){
            return (List<Integer>) new Random().ints(10,0,100).boxed().collect(Collectors.toCollection(() -> {
                try {
                    return base.getClass().newInstance();
                } catch (Exception ex) {
                    // Default
                    return new ArrayList<>();
                }
            }));
        }
    }
    

    然后这样称呼它:

    public class Main {
        public static void main(String[] args) throws Exception {
            List linkedList = new LinkedList<Integer>();
            Print printer = new printImpl();
            linkedList = fillRandom.IntFill(linkedList);
            printer.print(linkedList);
    
        }
    }
    

    还请注意,当您进行收集时,您正在创建一个全新的列表,而不是填充您已经创建的列表。然后,当您将其分配给变量时,您将替换旧变量。

    【讨论】:

      【解决方案3】:
          List linkedList = new LinkedList<Integer>();
          List<Integer> list = (LinkedList)fillRandom.IntFill();
          linkedList = new LinkedList<>(list);
          System.out.println(linkedList);
      

      这段代码应该适合你

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-24
        • 2019-10-13
        • 1970-01-01
        • 2020-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多