是否可以在Java 8中强制转换流?

Phi*_*ion 139 java java-8 java-stream

是否可以在Java 8中强制转换流?假设我有一个对象列表,我可以做这样的事情来过滤掉所有其他对象:

Stream.of(objects).filter(c -> c instanceof Client)
Run Code Online (Sandbox Code Playgroud)

在此之后,如果我想对客户做一些事情,我需要投下每个客户:

Stream.of(objects).filter(c -> c instanceof Client)
    .map(c -> ((Client) c).getID()).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

这看起来有点难看.是否可以将整个流转换为其他类型?像流延Stream<Object>Stream<Client>

请忽略这样的事实,即做这样的事情可能意味着糟糕的设计.我们在计算机科学课上做这样的事情,所以我正在研究java 8的新功能,如果可能的话,我很好奇.

ass*_*ias 251

我不认为有办法开箱即用.一个可能更清洁的解决方案是:

Stream.of(objects)
    .filter(c -> c instanceof Client)
    .map(c -> (Client) c)
    .map(Client::getID)
    .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

或者,如评论中所建议的那样,您可以使用该cast方法 - 前者可能更容易阅读:

Stream.of(objects)
    .filter(Client.class::isInstance)
    .map(Client.class::cast)
    .map(Client::getID)
    .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用以下命令"简化"instanceOf过滤器:`Stream.of(objects).filter(Client.class :: isInstance).[...]` (34认同)
  • `.map(Client.class :: cast)`也可以吗? (17认同)

Rea*_*ted 13

按照ggovan的回答,我这样做如下:

/**
 * Provides various high-order functions.
 */
public final class F {
    /**
     * When the returned {@code Function} is passed as an argument to
     * {@link Stream#flatMap}, the result is a stream of instances of
     * {@code cls}.
     */
    public static <E> Function<Object, Stream<E>> instancesOf(Class<E> cls) {
        return o -> cls.isInstance(o)
                ? Stream.of(cls.cast(o))
                : Stream.empty();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这个辅助函数:

Stream.of(objects).flatMap(F.instancesOf(Client.class))
        .map(Client::getId)
        .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)


ggo*_*van 9

迟到了,但我认为这是一个有用的答案.

flatMap 这将是最短的方式.

Stream.of(objects).flatMap(o->(o instanceof Client)?Stream.of((Client)o):Stream.empty())
Run Code Online (Sandbox Code Playgroud)

如果o是a Client然后使用单个元素创建Stream,否则使用空流.然后将这些流扁平化为a Stream<Client>.

  • 实际上这比`Stream.of(objects).filter(o-> o instanceof Client).map(o - >(Client)o)`甚至`Stream.of(objects).filter(Client.class: :isInstance).MAP(Client.class :: CAST)`. (3认同)

Roh*_*ain 5

这看起来有点难看.是否可以将整个流转换为其他类型?像流延Stream<Object>Stream<Client>

不,这是不可能的.这在Java 8中并不新鲜.这是泛型的.A List<Object>不是超类型List<String>,所以你不能只是List<Object>一个人List<String>.

类似的是这里的问题.你可以不投Stream<Object>Stream<Client>.当然你可以像这样间接地施放它:

Stream<Client> intStream = (Stream<Client>) (Stream<?>)stream;
Run Code Online (Sandbox Code Playgroud)

但这不安全,可能会在运行时失败.其根本原因是Java中的泛型是使用擦除实现的.因此,没有关于Stream它在运行时的类型的类型信息.一切都是公正的Stream.

顺便说一句,你的方法有什么问题?看起来很好.

  • `C#中的@DR Generics是使用reification实现的,而在Java中,它是使用erasure实现的.两者都以不同的方式实现.因此,您不能指望它在两种语言中都以相同的方式工作. (2认同)
  • @RohitJain:我并不是在批评 Java 的通用概念,但是这个单一的结果仍然会产生丑陋的代码;-) (2认同)