web-dev-qa-db-fra.com

Convertir une boucle (while et for) en streaming

J'ai commencé à travailler avec Java 8 et à essayer de convertir certaines boucles et l'ancienne syntaxe de mon code en lambdas et en flux.

Ainsi, par exemple, j'essaye de convertir ceci en boucle et en boucle, mais je ne comprends pas bien:

List<String> list = new ArrayList<>();
if (!oldList.isEmpty()) {// old is a List<String>
    Iterator<String> itr = oldList.iterator();
    while (itr.hasNext()) {
        String line = (String) itr.next();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (line.startsWith(entry.getKey())) {
         String newline = line.replace(entry.getKey(),entry.getValue());
                list.add(newline);
            }
        }
    }
}

Je voulais savoir s'il était possible de convertir l'exemple ci-dessus en un seul flux comportant une boucle while à l'intérieur d'une boucle for.

5
Joe

Comme indiqué ci-dessus, utiliser des flux ici n'ajoute pas vraiment de valeur, car cela rend le code plus difficile à lire/à comprendre. Je comprends que vous le faites plus comme un exercice d'apprentissage. Cela étant dit, faire quelque chose comme ceci est une approche légèrement plus fonctionnelle car elle n'a pas pour effet secondaire d'ajouter à la liste depuis le flux lui-même:

list = oldList.stream().flatMap(line->
            map.entrySet().stream()
                    .filter(e->line.startsWith(e.getKey()))
                    .map(filteredEntry->line.replace(filteredEntry.getKey(),filteredEntry.getValue()))
        ).collect(Collectors.toList());
5
Chris

Je ne vois pas pourquoi vous voudriez utiliser des flux ici, mais c'est possible.

Créez des entrées de test:

List<String> oldList = Arrays.asList("adda","bddb","cddc");
Map<String,String> map = new HashMap<>();
map.put("a", "x");
map.put("b", "y");
map.put("c", "z");

List<String> list = new ArrayList<>();

Le code actuel:

oldList.stream()
    .forEach(line -> map.entrySet().stream()
            .filter(entry -> line.startsWith(entry.getKey()))
            .forEach(entry -> list.add(line.replace(entry.getKey(),entry.getValue()))));

Imprimer le résultat:

list.forEach(System.out::println);

Lequel est:

xddx
yddy
zddz
3
Robin Topper

Pour répondre à votre question, c'est un 1-liner:

List<String> list = oldList.stream()
    .filter(line -> map.keySet().stream().anyMatch(line::startsWith))
    .map(line -> map.entrySet().stream()
        .filter(entry -> line.startsWith(entry.getKey()))
        .map(entry -> line.replace(entry.getKey(), entry.getValue()))
        .findFirst().get())
    .collect(Collectors.toList());
3
Bohemian

Vous pouvez y parvenir avec un flux imbriqué dans un flux créé à partir de la liste oldList. Le flux imbriqué joue le rôle de mappage de la valeur actuelle de oldList avec un mappeur défini dans map, par ex.

public static void main(String[] args) {
    final List<String> oldList = Arrays.asList("asd-qwe", "zxc", "123");
    final Map<String, String> map = new HashMap<String, String>() {{
        put("asd", "zcx");
        put("12", "09");
        put("qq", "aa");
    }};

    List<String> result = oldList.stream()
            .map(line -> map.entrySet()
                    .stream()
                    .filter(entry -> line.startsWith(entry.getKey()))
                    .map(entry -> line.replace(entry.getKey(), entry.getValue()))
                    .collect(Collectors.toList())
            )
            .flatMap(Collection::stream)
            .collect(Collectors.toList());


    System.out.println(result);
}

L'exemple suivant produit une sortie comme:

[zcx-qwe, 093]

La solution suggérée peut être facilement mise en parallèle si nécessaire. Approche fonctionnelle sans effets secondaires.

1
Szymon Stepniak