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.
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());
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
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());
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.