可以在Java8中强制转换流吗?

可以在Java8中强制转换流吗?,java,java-8,java-stream,Java,Java 8,Java Stream,可以在Java8中强制转换流吗?假设我有一个对象列表,我可以这样做以过滤掉所有其他对象: Stream.of(objects).filter(c -> c instanceof Client) 然而,在此之后,如果我想与客户做一些事情,我需要对他们中的每一个进行投票: Stream.of(objects).filter(c -> c instanceof Client) .map(c -> ((Client) c).getID()).forEach(System.ou

可以在Java8中强制转换流吗?假设我有一个对象列表,我可以这样做以过滤掉所有其他对象:

Stream.of(objects).filter(c -> c instanceof Client)
然而,在此之后,如果我想与客户做一些事情,我需要对他们中的每一个进行投票:

Stream.of(objects).filter(c -> c instanceof Client)
    .map(c -> ((Client) c).getID()).forEach(System.out::println);
这看起来有点难看。是否可以将整个流强制转换为其他类型?像将
转换为


请忽略这样一个事实:这样做可能意味着糟糕的设计。在我的计算机科学课上,我们做了类似的事情,所以我研究了java 8的新功能,并好奇这是否可能。

我认为没有现成的方法。一种可能更清洁的解决方案是:

Stream.of(objects)
    .filter(c -> c instanceof Client)
    .map(c -> (Client) c)
    .map(Client::getID)
    .forEach(System.out::println);
或者,正如评论中所建议的,您可以使用
cast
方法-前者可能更容易阅读:

Stream.of(objects)
    .filter(Client.class::isInstance)
    .map(Client.class::cast)
    .map(Client::getID)
    .forEach(System.out::println);
这看起来有点难看。是否可以将整个流强制转换为其他类型?像将
转换为

不,那是不可能的。这在Java8中并不新鲜。这是泛型特有的。
列表
不是
列表
的超级类型,因此不能将
列表
强制转换为
列表

这里的问题也类似。您不能将
强制转换为
。当然,你可以这样间接地施展:

Stream<Client> intStream = (Stream<Client>) (Stream<?>)stream;
Stream intStream=(Stream)(Stream)Stream;
但这并不安全,可能会在运行时失败。其根本原因是,Java中的泛型是使用擦除实现的。因此,没有可用的类型信息来说明运行时是哪种类型的
流。一切都是


顺便说一句,你的方法有什么问题?我觉得不错。

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

flatMap
将是最短的方法

Stream.of(objects).flatMap(o->(o instanceof Client)?Stream.of((Client)o):Stream.empty())
如果
o
客户端
,则使用单个元素创建流,否则使用空流。然后,这些流将被展平为

,如下所示:

/**
 * 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();
    }
}

@
C
中的D.R.泛型是使用物化实现的,而在Java中,它是使用擦除实现的。两者都以不同的方式实现。所以你不能期望它在两种语言中都能以同样的方式工作。@D.R.我知道擦除对初学者理解Java中泛型的概念提出了许多问题。由于我不使用C#,所以我无法详细介绍比较。但IMO以这种方式实现它的全部动机是避免JVM实现中的重大更改。为什么它“在运行时肯定会失败”?正如您所说,没有(泛型)类型信息,因此运行时无需检查。如果输入了错误的类型,它可能会在运行时失败,但这一点没有“确定性”。@RohitJain:我不是在批评Java的泛型概念,但这一结果仍然会产生难看的代码;-)@Java泛型从git开始就是丑陋的。主要是C++的特性,从java运行时的角度来看,两种流类型已经是相同的,所以不需要强制转换。诀窍是偷偷地通过编译器。(也就是说,假设这样做有任何意义。)这正是我想要的。我想我忽略了在
map
中将其转换为客户机将返回
。谢谢+1有趣的新方法,尽管它们有可能使用新一代的意大利面代码(水平,而不是垂直)@Lordofpigs是的,它可以工作,尽管我不确定代码是否变得更清晰。我已经在我的答案中添加了这个想法。您可以使用:
Stream.of(objects).filter(Client.class::isInstance)。[…]
@T3rm1“简化”过滤器实例当您使用原始类型时,许多事情变得更加困难……我试图实现这一点,但收到警告说我的类“使用未经检查或不安全的操作”–这是意料之中的吗?不幸的是,是的。如果您使用的是
if/else
而不是
?:
运算符,则不会出现警告。请放心,您可以安全地取消警告。实际上,这比Stream.of(objects)。filter(o->o instanceof Client)。map(o->(Client)o)
甚至
Stream.of(objects)。filter(Client.class::isInstance)。map(Client.class::cast)
Stream.of(objects).flatMap(F.instancesOf(Client.class))
        .map(Client::getId)
        .forEach(System.out::println);