コレクションを簡単にフィルタリングするために、Java 8のラムダで遊んでいました。しかし、同じステートメント内で結果を新しいリストとして取得する簡潔な方法は見つかりませんでした。これが私の最も簡潔なアプローチです。
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);
ネット上の例は、新しい結果リストを生成せずに停止するため、私の質問には答えませんでした。もっと簡潔な方法があるはずです。 Stream
クラスがtoList()
、toSet()
、…のようなメソッドを持つことを私は予想していたでしょう…
変数targetLongList
を3行目で直接代入できる方法はありますか?
ストリームがシーケンシャルのままであれば、自分がしていることが最も簡単な方法かもしれません。そうでなければ、forEach
の前にsequential()を呼び出す必要があります。
[あとでの編集:sequential()への呼び出しが必要な理由は、ストリームが並列である場合、現状のコード(forEach(targetLongList::add)
)は無駄になるからです。それでも、forEach
は明示的に非決定的であるため、意図された効果を達成することはできません - 連続したストリームでさえ要素処理の順序は保証されません。正しい順序を保証するためにforEachOrdered
を使う必要があります。 Stream API設計者の意図は、以下のように、この状況でコレクタを使用することです。]
代替案は
targetLongList = sourceLongList.stream()
.filter(l -> l > 100)
.collect(Collectors.toList());
更新しました:
別のアプローチはCollectors.toList
を使うことです:
targetLongList =
sourceLongList.stream().
filter(l -> l > 100).
collect(Collectors.toList());
前の解決策:
別のアプローチはCollectors.toCollection
を使うことです:
targetLongList =
sourceLongList.stream().
filter(l -> l > 100).
collect(Collectors.toCollection(ArrayList::new));
それが私が望むものであるとき、私はArrayList
のためにコレクターを返すutilメソッドを使うのが好きです。
Collectors.toCollection(ArrayList::new)
を使った解決策は、このような一般的な操作には少しうるさいと思います。
例:
ArrayList<Long> result = sourceLongList.stream()
.filter(l -> l > 100)
.collect(toArrayList());
public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
return Collectors.toCollection(ArrayList::new);
}
この回答で、私はカスタムコレクターを作成して使用することがどれほど簡単であるかを実証したい、それは一般的に非常に有用です。
プリミティブの配列がある場合は、 Eclipse Collections にあるプリミティブコレクションを使用できます。
LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);
SourceLongListをList
から変更できない場合
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList =
ListAdapter.adapt(sourceLongList).select(l -> l > 100, new ArrayList<>());
LongStream
を使いたい場合:
long[] sourceLongs = new long[]{1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L};
LongList targetList =
LongStream.of(sourceLongs)
.filter(l -> l > 100)
.collect(LongArrayList::new, LongArrayList::add, LongArrayList::addAll);
注:私はEclipseコレクションの寄稿者です。
もう少し効率的な方法(ソースリストの作成とフィルタによる自動アンボックス化を避けます):
List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
.filter(l -> l > 100)
.boxed()
.collect(Collectors.toList());
collect(Collectors.toList());
これは、StreamをListに変換するために使用できる呼び出しです。
サードパーティのライブラリを使っても構わないのなら、AOLの cyclops-react lib(私は寄稿者です)は List を含むすべての JDK Collection タイプの拡張機能を持っています。 ListXインタフェースはJava.util.Listを拡張し、フィルタを含む多数の便利な演算子を追加します。
あなたは簡単に書くことができます -
ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);
ListXは既存のListから(ListX.fromIterableを使って)作成することもできます。
LongStreamクラスと同様にIntStreamクラスとDoubleStreamクラスによっても提供されるcollectメソッドの別の変形があります。
<R> R collect(Supplier<R> supplier,
ObjLongConsumer<R> accumulator,
BiConsumer<R,R> combiner)
このストリームの要素に対して可変の縮小操作を実行します。可変縮小は、縮小された値がArrayListなどの可変結果コンテナであり、結果を置き換えるのではなく結果の状態を更新することによって要素が組み込まれるものです。これは以下と同等の結果を生成します。
R result = supplier.get();
for (long element : this stream)
accumulator.accept(result, element);
return result;
reduce(long、LongBinaryOperator)のように、追加の同期を必要とせずに収集操作を並列化できます。これは端末操作です。
そして、このcollectメソッドであなたの質問に答えるのは以下の通りです:
LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
.collect(ArrayList::new, (list, value) -> list.add(value)
, (list1, list2) -> list1.addAll(list2));
以下は非常にスマートなメソッド参照バリアントですが、理解が難しいものもあります。
LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
.collect(ArrayList::new, List::add , List::addAll);
以下はHashSetの変形です。
LongStream.of(1L, 2L, 3L, 3).filter(i -> i > 2)
.collect(HashSet::new, HashSet::add, HashSet::addAll);
同様にLinkedListの亜種はこのようなものです:
LongStream.of(1L, 2L, 3L, 3L)
.filter(i -> i > 2)
.collect(LinkedList::new, LinkedList::add, LinkedList::addAll);
以下のようにコードを書き直すことができます:
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = sourceLongList.stream().filter(l -> l > 100).collect(Collectors.toList());
(私のような)誰かがプリミティブ型の代わりにオブジェクトを扱う方法を探しているのであれば mapToObj()
を使ってください。
String ss = "An alternative way is to insert the following VM option before "
+ "the -vmargs option in the Eclipse shortcut properties(edit the "
+ "field Target inside the Shortcut tab):";
List<Character> ll = ss
.chars()
.mapToObj(c -> new Character((char) c))
.collect(Collectors.toList());
System.out.println("List type: " + ll.getClass());
System.out.println("Elem type: " + ll.get(0).getClass());
ll.stream().limit(50).forEach(System.out::print);
プリント:
List type: class Java.util.ArrayList
Elem type: class Java.lang.Character
An alternative way is to insert the following VM o
String joined =
Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
.filter(s -> s != null && !s.isEmpty())
.collect(Collectors.joining(","));
これは AbacusUtil によるコードです。
LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();
開示:私はAbacusUtilの開発者です。