Java 8扩展流<T>

Lia*_*ris 6 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的主要方法:

int arr [] = {1,2,3,4,5,6};

Object array [] = ((StreamStuff)Arrays
            .stream(arr))
            .biggerThanFour()
            .toArray();
Run Code Online (Sandbox Code Playgroud)

我正在尝试将Stream转换为我的接口StreamStuff,并使用我的方法.

我收到以下错误:

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

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

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

我想知道这种事情是否可能,如果是这样,我该如何实现这一目标?作为参考,我有点使用这篇文章作为指导.

eri*_*son 6

您呼叫stream()Arrays类,它创建自己Stream没有给你任何的连接实现.您必须Stream自己制作,或者将您在其他地方获得的流包装起来,以便使这样的事情发挥作用.像这样的东西:

int[] filtered = new StreamStuff(Arrays.stream(arr)).biggerThanFour().toArray();
Run Code Online (Sandbox Code Playgroud)

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

int[] filtered = Arrays.stream(arr).filter(i -> i > 4).toArray();
Run Code Online (Sandbox Code Playgroud)

  • @LiamFerris是的,这是有道理的.您可以查看[`StreamEx`](https://github.com/amaembo/streamex)库以获取更多示例; 它甚至可以提供你所需要的东西. (3认同)
  • 更糟糕的是,`Arrays.stream(int [])`甚至没有返回`Stream` ...... (2认同)

Jar*_*lak 6

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

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
}
Run Code Online (Sandbox Code Playgroud)

您将不得不委托接口中的所有方法,因此该类将非常大。您可能会考虑添加一个类StreamWrapper,该类将从接口中委托所有方法,然后让您的实际类StreamStuff扩展StreamWrapper。这将允许您只使用自定义方法,StreamStuff而没有其他流方法。您还可以在StreamWrapperfinal 中创建所有覆盖的方法,以避免意外覆盖它们。

然后你可以像这样使用它:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

请注意,您的强制转换Double可能会抛出,ClassCastException因此您可能会考虑将 generic 替换TDouble,从而将委托流限制为该特定类型。

  • 除了,一旦你调用一个真正的 Stream 方法,它就会返回一个 Stream,而不是一个 MyStream。因此,例如,您不能先调用 `map()`,然后再调用 `biggerThanFour`。您需要在每个阶段包装结果并协变覆盖所有流承载方法。 (4认同)
  • 您*可以*更改返回类型,如果您要缩小类型,那么通过将返回类型从 `Stream&lt;X&gt;` 更改为 `MyStream&lt;X&gt;` 来实现流方法是没有问题的。这意味着您必须重新包装每个中间操作的结果,例如`@Override public MyStream&lt;T&gt; filter(Predicate&lt;? super T&gt; predicate) { return new MyStream&lt;&gt;(delegate.filter(predicate)); }`。它与您现有的代码没有什么不同。 (4认同)