web-dev-qa-db-fra.com

Convertir une boucle pour concatiler String en une expression lambda

J'ai la boucle for suivante qui parcourt une liste de chaînes et stocke le premier caractère de chaque mot dans un StringBuilder. Je voudrais savoir comment puis-je transformer cela en une expression lambda

StringBuilder chars = new StringBuilder();
for (String l : list) {
    chars.append(l.charAt(0));
}  
22
Faktor 10

En supposant que vous appeliez ensuite toString() sur la StringBuilder, je pense que vous recherchez simplement Collectors.joining() , après avoir mappé chaque chaîne sur une sous-chaîne à un caractère:

String result = list
    .stream()
    .map(s -> s.substring(0, 1))
    .collect(Collectors.joining());

Exemple de code:

import Java.util.*;
import Java.util.stream.*;

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("foo");
        list.add("bar");
        list.add("baz");
        String result = list
            .stream()
            .map(s -> s.substring(0, 1))
            .collect(Collectors.joining());
        System.out.println(result); // fbb
    }
}

Notez l'utilisation de substring au lieu de charAt, nous avons donc toujours un flux de chaînes avec lequel travailler.

37
Jon Skeet

Des tonnes de façons de faire cela - l’option la plus simple: tenez-vous à ajouter à un StringBuilder et faites ceci:

    final StringBuilder chars = new StringBuilder();

    list.forEach(l -> chars.append(l.charAt(0)));
17
Fritz Duchardt

Sans créer de nombreux objets String intermédiaires, vous pouvez le faire comme ceci:

StringBuilder sb = list.stream()
                       .mapToInt(l -> l.codePointAt(0))
                       .collect(StringBuilder::new, 
                                StringBuilder::appendCodePoint, 
                                StringBuilder::append);

Notez que l'utilisation de codePointAt est bien meilleure que charAt comme si votre chaîne commençait par une paire de substitution. Si vous utilisiez charAt, vous obtiendrez peut-être un résultat imprévisible.

12
Tagir Valeev

Voici trois solutions différentes à ce problème. Chaque solution filtre les chaînes vides en premier, sinon StringIndexOutOfBoundsException peut être lancé. 

Cette solution est la même que celle de Tagir avec le code ajouté pour le filtrage des chaînes vides. Je l'ai inclus ici principalement pour comparer les deux autres solutions que j'ai fournies.

List<String> list =
    Arrays.asList("the", "", "quick", "", "brown", "", "fox");
StringBuilder builder = list.stream()
    .filter(s -> !s.isEmpty())
    .mapToInt(s -> s.codePointAt(0))
    .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append);
String result = builder.toString();
Assert.assertEquals("tqbf", result);

La seconde solution utilise Eclipse Collections et utilise un type de conteneur relativement nouveau appelé CodePointAdapter ajouté dans la version 7.0.

MutableList<String> list =
    Lists.mutable.with("the", "", "quick", "", "brown", "", "fox");
LazyIntIterable iterable = list.asLazy()
    .reject(String::isEmpty)
    .collectInt(s -> s.codePointAt(0));
String result = CodePointAdapter.from(iterable).toString();
Assert.assertEquals("tqbf", result);

La troisième solution utilise à nouveau Eclipse Collections, mais avec injectInto et StringBuilder au lieu de CodePointAdapter.

MutableList<String> list =
    Lists.mutable.with("the", "", "quick", "", "brown", "", "fox");
StringBuilder builder = list.asLazy()
    .reject(String::isEmpty)
    .collectInt(s -> s.codePointAt(0))
    .injectInto(new StringBuilder(), StringBuilder::appendCodePoint);
String result = builder.toString();
Assert.assertEquals("tqbf", result);

Remarque: je suis un partisan des collections Eclipse.

3
Donald Raab

Manière simple en utilisant la référence de la méthode:

List<String> list = Arrays.asList("ABC", "CDE");
StringBuilder sb = new StringBuilder();

list.forEach(sb::append);

String concatString = sb.toString();
0
Rahul Chauhan