Java 8扩展流<t>

时间:2016-10-11 14:51:01

标签: java casting java-8 java-stream

我正在尝试扩展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,并使用我的方法。

我收到以下错误:

  

线程“main”中的异常java.lang.ClassCastException:java.util.stream.IntPipeline $ Head无法强制转换为StreamStuff

当我这样做时,我得到同样的错误:

StreamStuff ss = (StreamStuff)Arrays.stream(arr);

我想知道这种事情是否可能,如果是这样,我该如何实现这一目标?作为参考,我使用this article作为指导。

3 个答案:

答案 0 :(得分:6)

您正在stream()类上调用Arrays,该类会创建自己的Stream实现,而与您的任何连接都没有任何关联。您必须自己生成Stream,或者将您在其他地方获得的流包装起来,以便这样的事情发挥作用。像这样:

int[] filtered = new StreamStuff(Arrays.stream(arr)).biggerThanFour().toArray();

但是,在您的情况下,为什么不过滤?

int[] filtered = Arrays.stream(arr).filter(i -> i > 4).toArray();

答案 1 :(得分:4)

如前所述,您可以创建自己的包装器实现:

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);
}

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

请注意,您向[{1}}投射可能会抛出Double,因此您可能会考虑将ClassCastException替换为T,因此将代理流限制为该特定类型

答案 2 :(得分:1)

另一种可能性是,如果您不希望将来处理所有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(...),再一次{{1方法但使用stream(...)作为参数来处理基本流中间方法,当然还有自定义方法,如Function<T,U>。 所以缺点是你不能直接从biggerThanFour()扩展(不幸的是Stream<T>不仅有一个标准实现的默认方法) 绕过代表。
处理也是一个小缺点,但我认为在大多数情况下它很好,例如:

Stream<T>

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