web-dev-qa-db-fra.com

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

Est-il possible de lancer un flux dans Java 8? Disons que j'ai une liste d'objets, je peux faire quelque chose comme ceci 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, j’ai besoin de lancer chacun d’eux:

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

Cela semble un peu moche. Est-il possible de convertir un flux entier dans un type différent? Comme cast Stream<Object> en Stream<Client>?

Ignorez s'il vous plaît le fait que de telles choses signifieraient probablement une mauvaise conception. Nous faisons ce genre de choses dans mon cours d'informatique. J'étais donc à la recherche des nouvelles fonctionnalités de Java 8 et étais curieux de savoir si cela était possible.

133
Phiction

Je ne pense pas qu'il y ait un moyen de faire ça tout de suite. Une solution éventuellement 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, cependant:

Stream.of(objects)
    .filter(Client.class::isInstance)
    .map(Client.class::cast)
    .map(Client::getID)
    .forEach(System.out::println);
231
assylias

Dans le sens de 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();
    }
}

En utilisant cette fonction d'assistance:

Stream.of(objects).flatMap(F.instancesOf(Client.class))
        .map(Client::getId)
        .forEach(System.out::println);
13
Brandon Mintern

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, créez un Stream avec un seul élément, sinon utilisez le flux vide. Ces flux seront ensuite aplatis dans un Stream<Client>.

9
ggovan

Cela semble un peu moche. Est-il possible de convertir un flux entier dans un type différent? Comme cast Stream<Object> en 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 convertir 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 peut échouer au moment de l'exécution. La raison sous-jacente à cela est que les génériques dans Java sont implémentés à l’aide de erasure. Donc, il n'y a aucune information de type disponible sur le type de Stream qu'il est au moment de l'exécution. Tout est juste Stream.

BTW, quel est le problème avec votre approche? Ca me va.

5
Rohit Jain