it-swarm.com.ru

Можно ли привести поток в Java 8?

Можно ли привести поток в 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 и мне было любопытно, возможно ли это.

125
Phiction

Я не думаю, что есть способ сделать это из коробки. Возможно более чистое решение было бы:

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

В соответствии с ответ 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);
13
Brandon Mintern

Поздно на вечеринку, но я думаю, что это полезный ответ.

flatMap будет самым коротким способом сделать это.

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

Если o является Client, тогда создайте поток с одним элементом, в противном случае используйте пустой поток. Эти потоки будут затем сведены в Stream<Client>.

9
ggovan

Это выглядит немного некрасиво. Можно ли привести весь поток к другому типу? Как приведение Stream<Object> к Stream<Client>?

Нет, это было бы невозможно. Это не ново в Java 8. Это относится к универсальным. List<Object> не является супертипом List<String>, поэтому вы не можете просто привести List<Object> к List<String>.

Подобная проблема здесь. Вы не можете привести Stream<Object> к Stream<Client>. Конечно, вы можете использовать его косвенно следующим образом:

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

но это небезопасно и может дать сбой во время выполнения. Основная причина этого заключается в том, что дженерики в Java реализованы с использованием стирания. Таким образом, нет никакой доступной информации о типе Stream во время выполнения. Все просто Stream.

Кстати, что не так с вашим подходом? Выглядит хорошо для меня.

5
Rohit Jain