Java 正在将流收集回相同的收集类型
假设我有一个未知类型的集合。我想做的是流式处理,在流上做一些事情,然后将其收集回与我的原始集合相同的集合类型。例如:Java 正在将流收集回相同的收集类型,java,java-8,java-stream,Java,Java 8,Java Stream,假设我有一个未知类型的集合。我想做的是流式处理,在流上做一些事情,然后将其收集回与我的原始集合相同的集合类型。例如: Collection<? extends Integer> getBigger(Collection<? extends Integer> col, int value) { return col.stream().filter(v -> v > value).collect(????); } Collection如果不违反构建Ja
Collection<? extends Integer> getBigger(Collection<? extends Integer> col, int value) {
return col.stream().filter(v -> v > value).collect(????);
}
Collection如果不违反构建Java streams框架所依据的原则,这是不可能的。这将完全违背从物理表示中提取流的想法
批量数据操作的顺序在管道中进行,请参见下图:
流在某种程度上类似于-在调用终端操作之前,它不会具体化。流处理是完全抽象的,与原始流源分离
如果您想在原始数据存储中以如此低的级别工作,不要因为简单地避开流而感到羞愧。它们只是一种工具,不是什么神圣的东西。通过引入流,好的旧集合仍然像以前一样好,具有内部迭代(新方法)的附加值
添加以满足您的好奇心:)
可能的解决方案如下。我自己也不喜欢它,而且我还不能解决那里所有的泛型问题,但它有局限性
其思想是创建一个与输入集合返回相同类型的收集器。但是,并非所有集合都提供空构造函数(没有参数),没有空构造函数,方法就无法工作。在lambda表达式中还存在检查异常的尴尬问题。(在这个漂亮的回答中提到:)
public集合getBiggerThan(集合列,int值){
//下面的集合是一个罕见的例子
//使用原始类型。getClass返回col的运行时类型,以及
//在运行时,所有类型参数都已被擦除。
@抑制警告(“原始类型”)
最后一个类这里有两个问题:(1)输入及其结果的运行时类型(类),以及(2)输入及其结果的编译时类型
对于(1),这可能看起来很奇怪,但一般来说,在Java中不可能创建任意类实例的副本
如果类没有可访问的无参数构造函数或不可变,则可能无法工作。对象也可能不可克隆。因此,调用方需要传入负责创建正确结果类实例的供应商
对于(2),适当剂量的泛型可以使该类型在编译时安全
<T extends Comparable<T>, C extends Collection<T>> C getBigger(
C col, T value, Supplier<C> supplier) {
return col.stream()
.filter(v -> v.compareTo(value) > 0)
.collect(Collectors.toCollection(supplier::get));
}
由于实际的底层类型只知道是方法的被调用方,所以他们应该负责收集它到收集他们想要的任何类型(例如使用收集器.toCollection(CustomCollectionType::new);
)。因此,您的方法应该返回流
。根据方便程度,它可以采取收集
或流
。您想在流上做什么?这是否意味着您必须具有特定的流格式?Javadoc forgetClass
:“实际的结果类型是类,这种行为很有意义:getClass
返回运行时类,并且在运行时所有类型参数都已被删除。我认为我们已经发现了原始类型的一种罕见的适当用法!
public void test() {
final Collection<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
final Collection<Integer> arrayList = new ArrayList<>(numbers);
final Collection<Integer> arrayList2 = getBiggerThan(arrayList, 6);
System.out.println(arrayList2);
System.out.println(arrayList2.getClass());
System.out.println();
final Collection<Integer> set = new HashSet<>(arrayList);
final Collection<Integer> set2 = getBiggerThan(set, 6);
System.out.println(set2);
System.out.println(set2.getClass());
System.out.println();
// This does not work as Arrays.asList() is of a type
// java.util.Arrays$ArrayList which does not provide a nullary constructor
final Collection<Integer> numbers2 = getBiggerThan(numbers, 6);
}
<T extends Comparable<T>, C extends Collection<T>> C getBigger(
C col, T value, Supplier<C> supplier) {
return col.stream()
.filter(v -> v.compareTo(value) > 0)
.collect(Collectors.toCollection(supplier::get));
}
List<Integer> input1 = Arrays.asList(1, 4, 9, 13, 14, 22);
List<Integer> filtered1 = getBigger(input1, 10, ArrayList::new);
Set<String> input2 = new HashSet<>();
input2.add("foo");
input2.add("bar");
input2.add("baz");
input2.add("qux");
Set<String> filtered2 = getBigger(input2, "c", HashSet::new);