文字列のリストを反復処理し、各Wordの最初の文字をStringBuilder
に格納する次のforループがあります。これをラムダ式に変換する方法を知りたい
StringBuilder chars = new StringBuilder();
for (String l : list) {
chars.append(l.charAt(0));
}
後でStringBuilder
でtoString()
を呼び出すと仮定すると、各文字列を単一にマッピングした後、 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
を使用していることに注意してください。そのため、処理する文字列のストリームが残っています。
これを行うための多くの方法-最も単純なオプション:StringBuilder
への追加に固執し、これを行います:
final StringBuilder chars = new StringBuilder();
list.forEach(l -> chars.append(l.charAt(0)));
多くの中間文字列オブジェクトを作成せずに、次のようにすることができます。
StringBuilder sb = list.stream()
.mapToInt(l -> l.codePointAt(0))
.collect(StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append);
codePointAt
を使用すると、文字列がサロゲートペアで始まるかのようにcharAt
よりもはるかに優れていることに注意してください。charAt
を使用すると、予測できない結果が生じる可能性があります。
この問題に対する3つの異なる解決策を以下に示します。各ソリューションは、空の文字列を最初にフィルタリングします。そうしないと、StringIndexOutOfBoundsException
がスローされる場合があります。
このソリューションは、空の文字列をフィルタリングするためのコードが追加されたTagirのソリューションと同じです。主に、提供した他の2つのソリューションと比較するために、ここに含めました。
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);
2番目のソリューションは Eclipse Collections を使用し、バージョン7.0で追加された CodePointAdapter
と呼ばれる比較的新しいコンテナータイプを活用します。
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);
3番目のソリューションでは、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のコミッターです。
メソッド参照を使用した簡単な方法:
List<String> list = Arrays.asList("ABC", "CDE");
StringBuilder sb = new StringBuilder();
list.forEach(sb::append);
String concatString = sb.toString();