【问题标题】:Generic function stream.map通用函数stream.map
【发布时间】:2018-03-07 22:37:59
【问题描述】:

我目前有一个将流转换为相同类型的流的类测试。

class Test {
    private Function<A1, A1> a1Transform;
    private Function<A2, A2> a2Transform;

    public <T extends A> Stream<T> transform(Stream<T> input) {
        return input
            .filter(o -> o instanceof A1)
            .map(A1.class::cast)
            .map(a1Transform);
    }
}

代码不会编译,除非

  1. 我将返回类型设为Stream&lt;? super T&gt;
  2. 我添加一个.map(o -&gt; (T) o) 将其转换回T。

这两种解决方案都有什么好处。解决这个问题的更好方法是什么。

【问题讨论】:

  • map(A1.class::cast)之后,流的实际类型是Stream&lt;A1&gt;。返回类型Stream&lt;T&gt; 可能是错误的,但您需要告诉我们更多关于您尝试做什么的信息,然后我们才能告诉您对代码的正确更改是什么。
  • transform 的主体似乎只适用于Stream&lt;A1&gt;,那么为什么不将其声明为Stream&lt;A1&gt; transform(Stream&lt;A1&gt; input)filter-step 是必不可少的,还是要将Function&lt;A, A&gt; 作为第二个参数传递给transform
  • A1 只是一个例子。我可以有一个if 循环来检查要应用哪个转换。
  • 用例:我有一组关于实现接口的对象的转换。像 A1、A2、A3 都实现接口 A。现在根据流中对象的类型,我想应用适当的转换,然后返回结果流。 @Radiodef
  • 输入应与输出流具有相同的类型。示例:输入 Stream,我希望返回是 Stream 或 Input Stream,我希望返回是 Stream。因此,在上述问题中,输入将是 Stream 我将其转换为 A1,然后应用 a1Transform,然后再次将其转换为 A1

标签: java function generics lambda java-stream


【解决方案1】:

如果A1A2 等有一个共同的超类型A,那么您可以将方法更改为如下所示:

public Stream<A> transform(Stream<?> input) {
    return input.filter(o -> o instanceof A1)
                .map(o -> (A1) o)
                .map(a1Transform)
                .map(o -> (A) o);
}

方法无法返回,例如,或者 Stream&lt;A1&gt; Stream&lt;A2&gt; Stream&lt;A3&gt;,等等。你能做的最好的就是像上面那样,你返回一个Stream&lt;A&gt;,或者你可以返回一个Stream&lt;? extends A&gt;

如果返回具有元素确切类型的流真的很重要,那么您可以使用访问者模式之类的东西,并将访问者传递给方法,而不是直接返回流。

另一种可能的方式是调用者将Class 传递给方法:

public <T extends A> Stream<T> transform(Stream<?> input, Class<T> type) {
    return input...
                ...
                ...
                .map(type::cast);
}

但是,遇到此类问题通常表明您需要重新设计某些东西。一般来说,在面向对象的设计中,API 外部的代码不应该关心具有特定类型的对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    相关资源
    最近更新 更多