Récursive utilisation de Flux de données.flatMap()

Considérer la classe suivante:

public class Order {

    private String id;

    private List<Order> orders = new ArrayList<>();

    @Override
    public String toString() {
        return this.id;
    }

    //getters & setters
}

REMARQUE: Il est important de noter que je ne peut pas modifier cette classe, parce que je suis de les consommer, à partir d'une API externe.

Également envisager la hiérarchie suivante de commandes:

Order o1 = new Order();
o1.setId("1");
Order o11 = new Order();
o11.setId("1.1");
Order o111 = new Order();
o111.setId("1.1.1");
List<Order> o11Children = new ArrayList<>(Arrays.asList(o111));
o11.setOrders(o11Children);

Order o12 = new Order();
o12.setId("1.2");
List<Order> o1Children = new ArrayList<>(Arrays.asList(o11, o12));
o1.setOrders(o1Children);

Order o2 = new Order();
o2.setId("2");
Order o21 = new Order();
o21.setId("2.1");
Order o22 = new Order();
o22.setId("2.2");
Order o23 = new Order();
o23.setId("2.3");
List<Order> o2Children = new ArrayList<>(Arrays.asList(o21, o22, o23));
o2.setOrders(o2Children);

List<Order> orders = new ArrayList<>(Arrays.asList(o1, o2));

Qui pourrait être visuellement représentés de cette façon:

1
1.1
1.1.1
1.2
2
2.1
2.2
2.3

Maintenant, je veux aplatir cette hiérarchie des ordres dans un List, de sorte que je reçois le texte suivant:

[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]

J'ai réussi à le faire de manière récursive à l'aide de flatMap() (avec une classe helper), comme suit:

List<Order> flattened = orders.stream()
    .flatMap(Helper::flatten)
    .collect(Collectors.toList());

C'est la classe helper:

public final class Helper {

    private Helper() {
    }

    public static Stream<Order> flatten(Order order) {
        return Stream.concat(
            Stream.of(order), 
            order.getOrders().stream().flatMap(Helper::flatten)); //recursion here
    }
}

La ligne suivante:

System.out.println(flattened);

Produit la sortie suivante:

[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]

So far So good. Le résultat est absolument correcte.

Cependant, après la lecture de cette question, j'avais quelques inquiétudes concernant l'utilisation de flatMap() à l'intérieur d'une méthode récursive. En particulier, je voulais savoir comment le flux a été élargi (si c'est le terme). J'ai donc modifié le Helper classe et utilisé peek(System.out::println) pour vérifier:

public static final class Helper {

    private Helper() {
    }

    public static Stream<Order> flatten(Order order) {
        return Stream.concat(
            Stream.of(order), 
            order.getOrders().stream().flatMap(Helper::flatten))
        .peek(System.out::println);
    }
}

Et le résultat a été:

1
1.1
1.1
1.1.1
1.1.1
1.1.1
1.2
1.2
2
2.1
2.1
2.2
2.2
2.3
2.3

Je ne suis pas sûr si c'est la sortie qui doit être imprimé.

Alors, je me demande si c'est OK pour laisser intermédiaire flux contiennent les éléments répétés. En outre, quels sont les avantages et les inconvénients de cette approche? Est-il correct, après tout, à utiliser flatMap() de cette façon? Est-il une meilleure façon d'obtenir les mêmes?

  • Juste par curiosité: pourquoi avez-vous mis l'id après la création de l'ordre plutôt que d'en faire un argument du constructeur?
  • Je ne peux pas modifier le Order de classe depuis qu'il parte d'une API, je suis de la consommer.
  • Ah, je vois. Alors la majeure partie de ma réponse est assez inutile. Il pourrait être intéressant d'ajouter cette information à votre question.
  • Je vais modifier ça, merci.