StreamExの概要
1. 概要
Java 8の最もエキサイティングな機能の1つは、 Stream API です。これは、簡単に言えば、要素のシーケンスを処理するための強力なツールです。
StreamEx は、パフォーマンスの向上とともに、標準StreamAPIの追加機能を提供するライブラリです。
ここにいくつかのコア機能があります:
- 日常のタスクを実行するための短くて便利な方法
- 100% c元のJDKStreamsとの互換性
- 並列処理の使いやすさ:新しい機能は、並列ストリームを可能な限り活用します
- パフォーマンスと最小限のオーバーヘッド。 StreamEx で、標準の Streamと比較して少ないコードでタスクを解決できる場合、通常の方法よりも大幅に遅くなることはありません(場合によってはさらに速くなります)。
このチュートリアルでは、 StreamExAPIのいくつかの機能を紹介します。
2. 例の設定
StreamEx を使用するには、pom.xmlに次の依存関係を追加する必要があります。
<dependency>
<groupId>one.util</groupId>
<artifactId>streamex</artifactId>
<version>0.6.5</version>
</dependency>
ライブラリの最新バージョンは、 MavenCentralにあります。
このチュートリアルでは、単純なUserクラスを使用します。
public class User {
int id;
String name;
Role role = new Role();
// standard getters, setters, and constructors
}
そして、単純な Role クラス:
public class Role {
}
3. コレクターショートカットメソッド
Streams の最も一般的な端末操作の1つは、collect操作です。 これにより、Stream要素を選択したコレクションに再パッケージ化できます。
問題は、単純なシナリオではコードが不必要に冗長になる可能性があることです。
users.stream()
.map(User::getName)
.collect(Collectors.toList());
3.1. コレクションへの収集
現在、StreamExでは、 Collector を提供して、 List 、 Set、Map、InmutableList、などが必要であることを指定する必要はありません。
List<String> userNames = StreamEx.of(users)
.map(User::getName)
.toList();
Stream から要素を取得してコレクションに入れるよりも複雑な処理を実行する場合は、collect操作をAPIで引き続き使用できます。
3.2. 高度なコレクター
もう1つの省略形は、groupingByです。
Map<Role, List<User>> role2users = StreamEx.of(users)
.groupingBy(User::getRole);
これにより、メソッドリファレンスで指定されたキータイプの Map が生成され、SQLでのgroupby操作に似たものが生成されます。
プレーンなStream APIを使用して、次のように記述する必要があります。
Map<Role, List<User>> role2users = users.stream()
.collect(Collectors.groupingBy(User::getRole));
Collectors.joining():にも同様の省略形があります。
StreamEx.of(1, 2, 3)
.joining("; "); // "1; 2; 3"
Stream aのすべての要素を取得すると、それらすべてを連結するStringが生成されます。
4. 要素の追加、削除、選択
いくつかのシナリオでは、さまざまなタイプのオブジェクトのリストがあり、それらをタイプでフィルタリングする必要があります:
List usersAndRoles = Arrays.asList(new User(), new Role());
List<Role> roles = StreamEx.of(usersAndRoles)
.select(Role.class)
.toList();
この便利な操作で、 Stream、の開始または終了に要素を追加できます。
List<String> appendedUsers = StreamEx.of(users)
.map(User::getName)
.prepend("(none)")
.append("LAST")
.toList();
nonNull()を使用して不要なヌル要素を削除し、StreamをIterableとして使用できます。
for (String line : StreamEx.of(users).map(User::getName).nonNull()) {
System.out.println(line);
}
5. 数学演算とプリミティブ型のサポート
StreamEx は、この自明の例でわかるように、プリミティブ型のサポートを追加します。
short[] src = {1,2,3};
char[] output = IntStreamEx.of(src)
.map(x -> x * 5)
.toCharArray();
次に、double要素の配列を順序付けられていない方法で取得しましょう。 各ペアの差で構成される配列を作成します。
pairMap メソッドを使用して、この操作を実行できます。
public double[] getDiffBetweenPairs(double... numbers) {
return DoubleStreamEx.of(numbers)
.pairMap((a, b) -> b - a)
.toArray();
}
6. マップ操作
6.1. キーによるフィルタリング
もう1つの便利な機能は、MapからStreamを作成し、それらが指す値を使用して要素をフィルタリングする機能です。
この場合、null以外のすべての値を取得しています。
Map<String, Role> nameToRole = new HashMap<>();
nameToRole.put("first", new Role());
nameToRole.put("second", null);
Set<String> nonNullRoles = StreamEx.ofKeys(nameToRole, Objects::nonNull)
.toSet();
6.2. キーと値のペアの操作
EntryStream インスタンスを作成することにより、キーと値のペアを操作することもできます。
public Map<User, List<Role>> transformMap(
Map<Role, List<User>> role2users) {
Map<User, List<Role>> users2roles = EntryStream.of(role2users)
.flatMapValues(List::stream)
.invert()
.grouping();
return users2roles;
}
特別な操作EntryStream.ofは、 Map を受け取り、それをキー値オブジェクトのStreamに変換します。 次に、 flatMapValues 操作を使用して、役割のリストを単一値のStreamに変換します。
次に、キーと値のペアを反転して、 User クラスにキーを作成し、Roleクラスに値を設定します。
そして最後に、 grouping 操作を使用して、マップを受信したマップの反転に変換できます。すべて4つの操作で済みます。
6.3. キー値マッピング
キーと値を個別にマッピングすることもできます。
Map<String, String> mapToString = EntryStream.of(users2roles)
.mapKeys(String::valueOf)
.mapValues(String::valueOf)
.toMap();
これにより、キーまたは値を別の必要なタイプにすばやく変換できます。
7. ファイル操作
StreamEx を使用すると、ファイルを効率的に読み取ることができます。つまり、一度に完全なファイルをロードする必要はありません。 大きなファイルを処理するときに便利です。
StreamEx.ofLines(reader)
.remove(String::isEmpty)
.forEach(System.out::println);
remove()メソッドを使用して、空の行をフィルターで除去していることに注意してください。
ここで注意すべき点は、StreamExはファイルを自動的に閉じないということです。 したがって、不要なメモリオーバーヘッドを回避するために、ファイルの読み取りと書き込みの両方の機会に手動で閉じる操作を実行することを忘れないでください。
8. 結論
このチュートリアルでは、 StreamEx について学習しましたが、これはさまざまなユーティリティです。 やるべきことはまだたくさんあります–そして彼らは便利なチートシートここを持っています。
いつものように、完全なソースコードはGitHubでから入手できます。