web-dev-qa-db-fra.com

Java 8 flux sur des tableaux de chaînes

J'ai une seule chaîne de format:

row1col1 row1col2
row2col1 row2col2
row3col1 row3col2

etc...

Je veux extraire chaque élément et créer un tableau d'objets avec des propriétés comme ceci:

new MyObject(row1col1, row1col2); 

Je suis nouveau sur Java 8 et Streams et je voudrais savoir comment puis-je y parvenir sans boucles.

Normalement, j'utiliserais une String.split('\n') pour accumuler les lignes dans un tableau de String

Et puis une boucle où, pour chaque ligne, je diviserais à nouveau sur le séparateur d'espace et avec le tableau résultant des deux éléments (row1col1 row1col2) Construirais mon objet, jusqu'à ce qu'il n'y ait plus de lignes à traiter.

Comme ça:

String sausage = "row1col1 row1col2\nrow2col1 row2col2\nrow3col1 row3col2";
String[] rows = sausage.split("\n");

for (String row : rows) {
    String[] objectData = u.split("\\s+");
    MyObject myObject = new MyObject(objectData[0], objectData[1]);
    myObjectList.add(myObject);
}

Quelqu'un peut-il m'expliquer comment réaliser la même chose avec les flux et quel est le mécanisme qui me permet de le faire?

Est-ce même une façon de penser valable lors de l'augmentation du nombre d'éléments parce que de tous les exemples que j'ai vus, les flux se concentrent sur le filtrage, la collecte ou généralement donné un ensemble d'éléments récupérer un ensemble mineur en appliquant certains critères.

11
Lucian Enache

Un moyen simple serait de créer un Pattern avec le séparateur de ligne et de diviser l'entrée String en Stream. Ensuite, chaque ligne est séparée par un espace (ne gardant que 2 parties) et mappée sur un MyObject. Enfin, un tableau est construit avec le résultat.

public static void main(String[] args) {
    String str = "row1col1 row2col2\r\nrow2col1 row2col2\r\nrow3col1 row3col2";

    MyObject[] array =
        Pattern.compile(System.lineSeparator(), Pattern.LITERAL)
               .splitAsStream(str)
               .map(s -> s.split("\\s+", 2))
               .map(a -> new MyObject(a[0], a[1]))
               .toArray(MyObject[]::new);

    System.out.println(Arrays.toString(array));
}

L'utilisation de splitAsStream peut être avantageuse par rapport à Stream.of(...) si l'entrée String est longue.

J'ai supposé dans le code que le séparateur de ligne du String était le séparateur de ligne par défaut (System.lineSeparator()) du système d'exploitation, mais vous pouvez le changer s'il ne l'est pas.


Au lieu de cela, si vous lisez un fichier, vous pouvez utiliser Files.lines() pour obtenir un Stream de toutes les lignes du fichier:

MyObject[] array = Files.lines(path)
                        .map(s -> s.split("\\s+", 2))
                        .map(a -> new MyObject(a[0], a[1]))
                        .toArray(MyObject[]::new);

System.out.println(Arrays.toString(array));
11
Tunaki

Vous pouvez générer un Stream de Strings qui représente une seule instance de MyObject et les transformer chacun en votre instance de MyObject (en les séparant d'abord et puis construction d'une instance MyObject):

List<MyObject> list = 
   Stream.of(inputString.split("\n"))
      .map (s -> s.split(" "))
      .filter (arr -> arr.length == 2) // this validation may not be necessary
                                       // if you are sure each line contains 2 tokens
      .map (arr -> new MyObject(arr[0],arr[1]))
      .collect(Collectors.toList());
6
Eran