Est-il possible de lancer un flux en Java 8?


Est-il possible de lancer un flux en Java 8? Disons que j'ai une liste d'objets, je peux faire quelque chose comme ça pour filtrer tous les objets supplémentaires:

Stream.of(objects).filter(c -> c instanceof Client)

Après cela, si je veux faire quelque chose avec les clients, je devrais lancer chacun d'eux:

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

Cela a l'air un peu moche. Est-il possible de lancer un flux entier vers un type différent? Comme cast Stream<Object> à un Stream<Client>?

Veuillez ignorer le fait que faire des choses comme ça signifierait probablement une mauvaise conception. Nous faites des choses comme ça dans mon cours d'informatique, alors je regardais les nouvelles fonctionnalités de java 8 et j'étais curieux de savoir si cela était possible.

Author: Stuart Marks, 2014-03-19

4 answers

Je ne pense pas qu'il y ait un moyen de le faire hors de la boîte. Une solution peut-être plus propre serait:

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

Ou, comme suggéré dans les commentaires, vous pouvez utiliser la méthode cast - la première peut être plus facile à lire:

Stream.of(objects)
    .filter(Client.class::isInstance)
    .map(Client.class::cast)
    .map(Client::getID)
    .forEach(System.out::println);
 186
Author: assylias, 2017-03-22 16:31:09

Dans le sens de la réponse de ggovan , je le fais comme suit:

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

Utilisation de cette fonction d'aide:

Stream.of(objects).flatMap(F.instancesOf(Client.class))
        .map(Client::getId)
        .forEach(System.out::println);
 13
Author: Brandon Mintern, 2017-05-23 12:26:32

En retard à la fête, mais je pense que c'est une réponse utile.

flatMap serait le moyen le plus court de le faire.

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

Si o est un Client alors créez un flux avec un seul élément, sinon utilisez le flux vide. Ces flux seront ensuite aplatis en un Stream<Client>.

 9
Author: ggovan, 2014-05-05 13:19:45

Ça a l'air un peu moche. Est-il possible de lancer un flux entier vers un type différent? Comme cast Stream<Object> à un Stream<Client>?

Non, ce ne serait pas possible. Ce n'est pas nouveau dans Java 8. Ceci est spécifique aux génériques. Un List<Object> n'est pas un super type de List<String>, vous ne pouvez donc pas simplement lancer un List<Object> en List<String>.

Le problème est similaire ici. Vous ne pouvez pas convertir Stream<Object> en Stream<Client>. Bien sûr, vous pouvez le lancer indirectement comme ceci:

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

Mais ce n'est pas sûr, et pourrait échouer au moment de l'exécution. La raison sous-jacente à cela est que les génériques en Java sont implémentés à l'aide de l'effacement. Donc, il n'y a aucune information de type disponible sur le type de Stream qu'il est à l'exécution. Tout est juste Stream.

BTW, quel est le problème avec votre approche? Semble bien pour moi.

 5
Author: Rohit Jain, 2014-03-19 16:24:23