191

是否可以在 Java 8 中转换流?假设我有一个对象列表,我可以执行以下操作来过滤掉所有其他对象:

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

这看起来有点难看。是否可以将整个流转换为不同的类型?像投到Stream<Object>一个Stream<Client>

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

4

5 回答 5

342

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

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);
于 2014-03-19T16:16:01.660 回答
16

按照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();
    }
}

使用这个辅助函数:

Stream.of(objects).flatMap(F.instancesOf(Client.class))
        .map(Client::getId)
        .forEach(System.out::println);
于 2014-06-12T18:43:08.273 回答
12

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

flatMap将是最短的方法。

Stream.of(objects).flatMap(o->(o instanceof Client)?Stream.of((Client)o):Stream.empty())

如果o是 aClient则创建一个带有单个元素的 Stream,否则使用空流。然后这些流将被展平为Stream<Client>.

于 2014-05-05T13:19:45.680 回答
8

这看起来有点难看。是否可以将整个流转换为不同的类型?像投到Stream<Object>一个Stream<Client>

不,那是不可能的。这在 Java 8 中并不新鲜。这是特定于泛型的。AList<Object>不是 的超类型List<String>,因此您不能只将 a 强制List<Object>转换为 a List<String>

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

Stream<Client> intStream = (Stream<Client>) (Stream<?>)stream;

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

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

于 2014-03-19T16:16:20.877 回答
0

我发现在处理一个类的无类型集合时,您可以创建一个有类型的集合

UntypedObjCollection bag = some preGenerics method;
List<Foo> foolist = new ArrayList<>();
bag.stream().forEach(o ->fooList.add((Foo)o));

似乎没有一种方法可以一次性将 Object 投射到某物中并进行过滤、映射等。将 Object 放入类型化集合的唯一方法是终端操作。这是运行 JDK 17 并在尝试较少粒度的方法时处理 module.base 异常。

于 2021-12-02T13:31:03.380 回答