it-swarm.com.ru

Конвертировать цикл for для преобразования String в лямбда-выражение

У меня есть следующий цикл for, который перебирает список строк и сохраняет первый символ каждого слова в переменной StringBuilder. Я хотел бы знать, как я могу преобразовать это в лямбда-выражение

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

Предполагая, что вы впоследствии вызываете toString() для StringBuilder, я думаю, что вы просто ищете Collectors.joining() , после сопоставления каждой строки с односимвольной подстрокой:

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

Образец кода:

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
    }
}

Обратите внимание на использование substring вместо charAt, поэтому у нас все еще есть поток строк для работы.

37
Jon Skeet

Тонны способов сделать это - самый простой вариант : придерживаться добавления к StringBuilder и сделать это:

    final StringBuilder chars = new StringBuilder();

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

Не создавая много промежуточных объектов String, вы можете сделать это следующим образом:

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

Обратите внимание, что использование codePointAt намного лучше, чем charAt, так как если ваша строка начинается с суррогатной пары, то при использовании charAt вы можете получить непредсказуемый результат.

12
Tagir Valeev

Вот три разных решения этой проблемы. Каждое решение сначала фильтрует пустые строки, иначе может быть выброшено StringIndexOutOfBoundsException

Это решение аналогично решению из Тагира с добавленным кодом для фильтрации пустых строк. Я включил его здесь в первую очередь, чтобы сравнить с двумя другими решениями, которые я предоставил.

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

Второе решение использует Eclipse Collections и использует относительно новый тип контейнера под названием CodePointAdapter , который был добавлен в версии 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);

Третье решение снова использует Коллекции Eclipse, но с injectInto и StringBuilder вместо 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);

Примечание: я являюсь коммиттером для Eclipse Collections.

3
Donald Raab

Простой способ, используя ссылку на метод:

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

list.forEach(sb::append);

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