Java 8扩展Stream<T>

8
我将尝试扩展Java 8的Stream实现。
我有以下接口:
public interface StreamStuff<T> extends Stream<T> {

    Stream<T> delegate();
    default Stream<T> biggerThanFour() {
        return delegate().filter(i -> ((Double)i > 4));
    }
}

在我的主方法中:
int arr [] = {1,2,3,4,5,6};

Object array [] = ((StreamStuff)Arrays
            .stream(arr))
            .biggerThanFour()
            .toArray();

我正在尝试将Stream转换为我的接口StreamStuff,并使用我的方法。
我得到了以下错误:
“Exception in thread "main" java.lang.ClassCastException: java.util.stream.IntPipeline$Head cannot be cast to StreamStuff”
当我执行以下操作时,我会得到相同的错误:
“StreamStuff ss = (StreamStuff)Arrays.stream(arr);”
我想知道这种事情是否可能,如果可能,我该如何实现?作为参考,我在使用this article作为指南。

5
дҪ еёҢжңӣж–№жі•Arrays.streamеҰӮдҪ•зҹҘйҒ“дҪ жү©еұ•зҡ„жҺҘеҸЈпјҹеҶҚж¬ЎжҹҘзңӢж–Үз« пјҢзү№еҲ«жҳҜ他们зҡ„EnhancedListгҖӮ - Tunaki
可能是如何为Java实现Stream<T>的重复问题。 - the8472
3个回答

7
你正在调用Arrays类上的stream()方法,它会创建自己的Stream实现,并没有与你的实现相连。你需要自己生成Stream,或者包装你从别处获取的流,以使这样的操作生效。具体方法如下:
int[] filtered = new StreamStuff(Arrays.stream(arr)).biggerThanFour().toArray();

然而,在你的情况下,为什么不直接过滤呢?
int[] filtered = Arrays.stream(arr).filter(i -> i > 4).toArray();

1
.biggerThanFour() 方法是任意的。我正在尝试弄清楚如何编写自己的方法以在流管道中使用。如果有意义的话。 - Liam Ferris
4
@LiamFerris,好的,这很有道理。您可以查看StreamEx库,以获取更多示例;它甚至可能已经提供了您需要的内容。 - erickson
谢谢,我会看一下 :) 感谢帮助。 - Liam Ferris
2
更糟糕的是,Arrays.stream(int[])甚至不返回一个Stream... - Holger

7

正如已经提到的,您可以创建自己的包装器实现:

public class MyStream<T> implements Stream<T> {

    private final Stream<T> delegate;

    public MyStream(Stream<T> delegate) {
        this.delegate = delegate;
    }

    @Override
    public Stream<T> filter(Predicate<? super T> predicate) {
        return delegate.filter(predicate);
    }

    @Override
    public void forEach(Consumer<? super T> action) {
        delegate.forEach(action);
    }

    MyStream<T> biggerThanFour() {
        return new MyStream<>(delegate.filter(i -> ((Double) i > 4)));
    }

    // all other methods from the interface
}

您需要委托接口中的所有方法,因此该类会变得非常大。您可以考虑添加一个名为StreamWrapper的类,该类将从接口中委托所有方法,然后使您的实际类StreamStuff继承StreamWrapper。这将允许您在StreamStuff中仅使用自定义方法而没有其他流方法。您还可以使StreamWrapper中所有重写的方法都是final的,以避免意外覆盖它们。
然后您可以按照以下方式使用它:
public static void main(String[] args) {
    Stream<Double> orgStream = Stream.of(1.0, 3.0, 7.0, 2.0, 9.0);

    MyStream<Double> myStream = new MyStream<>(orgStream);

    myStream.biggerThanFour().forEach(System.out::println);
}

自定义方法返回一个新的包装器,因此您可以链接调用自定义方法。

请注意,您对 Double 的转换可能会抛出 ClassCastException,因此您可以考虑将通用的 T 替换为 Double,从而限制委托流为特定类型。


6
但是,一旦调用真正的Stream方法,它将返回一个Stream,而不是MyStream。因此,您不能例如调用map()然后调用biggerThanFour。您需要在每个阶段包装结果,并协变地覆盖所有流相关的方法。 - Brian Goetz
1
@BrianGoetz 很好的观点。这实际上意味着重新实现Stream API,因为如果我们想要更改返回类型,就不能再使用Stream接口了... - Jaroslaw Pawlak
4
如果你正在缩小类型,那么可以更改返回类型,因此通过将返回类型从 Stream<X> 更改为 MyStream<X> 来实现流方法没有问题。这意味着您必须重新包装每个中间操作的结果,例如 @Override public MyStream<T> filter(Predicate<? super T> predicate) { return new MyStream<>(delegate.filter(predicate)); }。这与您现有的代码并没有太大区别。 - Holger

2
另一个可能的选择是,如果您不想在未来处理所有的Stream<T>代理和新方法,可以使用一个带有更包装的lambda流方法的接口:
public interface MyStream<T> {

    Stream<T> stream();

    static <T> MyStream<T> of(Stream<T> stream) {
        return () -> stream;
    }

    default <U> MyStream<U> stream(Function<Stream<T>, Stream<U>> stream) {
        return of(stream.apply(stream()));
    }

    //Watch out with Double cast. Check the type in method or restrict it via generic
    default MyStream<T> biggerThanFour() {
        return of(stream().filter(i -> ((Double) i > 4)));
    }

    //Watch out with Double cast. Check the type in method or restrict it via generic
    //Another method
    default MyStream<T> biggerThanFourteen() {
        return of(stream().filter(i -> ((Double) i > 14)));
    }
}

您有一个接口,其中包含处理基础流终端方法的stream()方法,
静态创建方法of(...)
再次是stream(...)方法,但参数为Function<T,U>以处理基础流中间方法
当然还有自定义方法,例如biggerThanFour()

缺点在于您无法直接从Stream<T>扩展(不幸的是,Stream<T>不仅具有默认方法,而且只有一种标准实现)来绕过委托。
此外,处理也是一个小缺点,但我认为在大多数情况下都可以,例如:

List<Integer> doubles = MyStream.of(Stream.of(1.0, 3.0, 7.0, 2.0, 9.0)) // create instance
                .biggerThanFour() //call MyStream methods
                .stream(doubleStream -> doubleStream.map(aDouble -> aDouble * 2)) //Do youre base stream intermediate methods and return again MyStream so you can call more specific custom methods
                .biggerThanFourteen()
                .stream() // call the base stream more or less your delegate for last intermediate methods and terminal method
                .mapToInt(Double::intValue)
                .boxed() //Ah if you have IntStreams and similar you can call the boxed() method to get an equivalent stream method.
                .collect(Collectors.toList()); // terminal method call

所以列表内容是[18] ;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接