Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/360.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_Java 8_Java Stream - Fatal编程技术网

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 for
getClass
:“实际的结果类型是
类,这种行为很有意义:
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);