Convert a for loop to concat String into a lambda expression

六月ゝ 毕业季﹏ 提交于 2019-12-03 01:17:01

Assuming you call toString() on the StringBuilder afterwards, I think you're just looking for Collectors.joining(), after mapping each string to a single-character substring:

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

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

Note the use of substring instead of charAt, so we still have a stream of strings to work with.

Tons of ways to do this - the most simple option: stick to adding to a StringBuilder and do this:

    final StringBuilder chars = new StringBuilder();

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

Without creating many intermediate String objects you can do it like this:

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

Note that using codePointAt is much better than charAt as if your string starts with surrogate pair, using charAt you may have an unpredictable result.

Donald Raab

Here are three different solutions to this problem. Each solution filters empty strings first as otherwise StringIndexOutOfBoundsException may be thrown.

This solution is the same as the solution from Tagir with the added code for filtering empty strings. I included it here primarily to compare to the other two solutions I have provided.

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

The second solution uses Eclipse Collections, and leverages a relatively new container type called CodePointAdapter that was added in 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);

The third solution uses Eclipse Collections again, but with injectInto and StringBuilder instead of 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);

Note: I am a committer for Eclipse Collections.

Simple way using method reference :

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

list.forEach(sb::append);

String concatString = sb.toString();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!