「プログラミング」カテゴリーアーカイブ

【プログラミング(JAVA)】Stream APIについて

Java 8で導入されたStream APIは、コレクションや配列などのデータソースに対して、データの操作を宣言的に行うための強力なツールです。この記事では、Stream APIの基本文法、コードサンプル、応用的な使い方、利用ケース、実装時の注意点について詳しく解説します。

Stream APIとは?

Stream APIは、データ処理のための宣言的なアプローチを提供します。従来の外部イテレーション(forループなど)と異なり、内部イテレーションを使用して、データを操作します。これにより、コードが簡潔かつ読みやすくなり、並列処理の恩恵も得やすくなります。

基本文法

Stream APIの基本的な流れは次のようになります。

  1. データソース: コレクションや配列、ファイルなどからStreamを生成します。
  2. 中間操作: フィルタリング、マッピング、ソートなどの操作を行います。中間操作は遅延評価されます。
  3. 終端操作: 集約、収集、出力などの操作を行います。終端操作が実行されると、Streamは消費されます。

基本的な操作例

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");

List<String> result = names.stream()
.filter(name -> name.startsWith("J")) // フィルタリング
.map(String::toUpperCase) // 文字列を大文字に変換
.sorted() // アルファベット順にソート
.collect(Collectors.toList()); // 結果をリストに収集

result.forEach(System.out::println); // 結果を出力
}
}

応用的な使い方

Stream APIは、基本的なフィルタリングやマッピングだけでなく、複雑なデータ処理も簡潔に表現できます。以下に、いくつかの応用的な使い方を紹介します。

1. 複数条件のフィルタリング

List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("J") && name.length() > 3)
.collect(Collectors.toList());

2. 並列ストリームを使用したパフォーマンス向上

並列ストリームを使用すると、大量のデータを効率的に処理できます。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream()
.reduce(0, Integer::sum); // 並列で集約処理

3. グループ化と集計

Collectors.groupingByを使用して、データをグループ化し、さらに集計処理を行います。

import java.util.Map;
import java.util.stream.Collectors;

Map<Integer, List<String>> groupedByLength = names.stream()
.collect(Collectors.groupingBy(String::length));

4. Optionalと組み合わせた利用

Stream APIとOptionalを組み合わせることで、安全な処理を実現できます。

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class StreamOptionalExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");

// Streamでフィルタリングして最初の要素を取得
Optional<String> firstNameStartingWithJ = names.stream()
.filter(name -> name.startsWith("J"))
.findFirst();

// Optionalを使って結果を安全に扱う
firstNameStartingWithJ.ifPresentOrElse(
name -> System.out.println("First name starting with J: " + name),
() -> System.out.println("No name starting with J found")
);
}

※findFirst()やfindAny()といった終端操作は、該当する要素が見つからない場合にOptionalを返します。これにより、結果が存在しないケースにも安全に対処できます。

解説
  • filter: Stream内で特定の条件に合致する要素をフィルタリングします。
  • findFirst:条件に合致する最初の要素をOptionalとして返します。
  • Optional.ifPresentOrElse :値が存在する場合には処理を行い、存在しない場合には代替の処理を行います。

Stream APIを利用すべきケース

Stream APIは以下のようなケースで有効です。

  • 大量のデータを効率的に処理したい場合: 内部イテレーションによる遅延評価と並列処理の組み合わせにより、大規模データを効率的に処理できます。
  • コードの可読性を向上させたい場合: Stream APIを使用すると、複雑な処理を簡潔に表現できます。
  • データの変換、フィルタリング、集計が必要な場合: Stream APIは、データの操作をチェーン形式で記述でき、柔軟かつ強力なデータ処理が可能です。

実装時に気を付けるべき事項

  1. 遅延評価の理解
    Streamの中間操作は遅延評価され、終端操作が実行されるまで実行されません。この特性を理解していないと、意図しない結果を招くことがあります。
  2. 並列ストリームの適用
    並列ストリームを使用することでパフォーマンスが向上することがありますが、適用が不適切な場合、逆にオーバーヘッドが発生することがあります。データのサイズや処理の内容に応じて適用を判断する必要があります。
  3. 可変データ構造の扱い
    可変データ構造(例: リスト)をStream APIで操作する際、破壊的な変更が加わらないように注意が必要です。並列処理では特に注意が必要です。
  4. 終端操作の一度限りの利用
    Streamは一度消費されると再利用できません。同じデータに対して複数回の操作が必要な場合は、新しいStreamを生成する必要があります。

公式ドキュメント

詳細なリファレンスや追加の情報は、公式ドキュメントを参照してください。

まとめ

Java Stream APIは、コレクションや配列などのデータを効率的に操作するための強力なツールです。基本的なフィルタリングやマッピングから、並列処理やグループ化、Optionalとの組み合わせまで、さまざまな操作を簡潔に記述できます。適切なケースで利用することで、コードの可読性やパフォーマンスを向上させることが可能です。ただし、遅延評価や並列処理の特性を理解し、実装時の注意点を守ることが重要です。

【プログラミング(JAVA)】Ver12以降のAPI差分一覧

Javaはバージョンごとに新しいAPIや機能が追加され、開発者にとってはこれらの変更を把握することが重要です。本記事では、Java 12以降の各バージョンごとの主要なAPI差分を一覧形式で紹介します。各バージョンの新機能や変更点を理解することで、最新のJavaを効果的に活用できます。

参考サイト


Java 12 (2019年3月)

  • JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)
    新しいガベージコレクターShenandoahが追加され、低レイテンシアプリケーションに対応しました。
  • JEP 334: JVM Constants API
    新しいjava.lang.invoke.constantパッケージが追加され、定数プールの管理が強化されました。
  • JEP 325: Switch Expressions (Preview)
    switch文が式として使用可能になり、コードの簡潔さと安全性が向上しました。

Java 13 (2019年9月)

  • JEP 354: Switch Expressions (Preview)
    Java 12で導入されたswitch式が改善され、再度プレビューとして提供されました。
  • JEP 355: Text Blocks (Preview)
    複数行の文字列を簡単に記述できる「テキストブロック」が導入され、可読性が向上しました。
  • JEP 350: Dynamic CDS Archives
    クラスデータ共有(CDS)アーカイブを動的に作成できるようになり、アプリケーションの起動時間が短縮されました。

Java 14 (2020年3月)

  • JEP 361: Switch Expressions
    switch式が正式に導入され、プレビューから標準機能になりました。
  • JEP 368: Text Blocks
    複数行文字列の記述が正式にサポートされ、コードの記述が簡潔に。
  • JEP 359: Records (Preview)
    データキャリア用のクラスを簡単に定義できるrecordがプレビュー機能として導入。
  • JEP 305: Pattern Matching for instanceof (Preview)
    instanceof演算子にパターンマッチングが追加され、キャストの冗長性が減少。

Java 15 (2020年9月)

  • JEP 360: Sealed Classes (Preview)
    クラス階層を制限できるシールドクラスが導入され、コードの安全性が向上。
  • JEP 378: Text Blocks
    テキストブロックが標準機能に。
  • JEP 339: Edwards-Curve Digital Signature Algorithm (EdDSA)
    セキュリティアルゴリズムとしてEdDSAが追加されました。
  • JEP 371: Hidden Classes
    JVMで動的に生成され、外部からのアクセスを制限できる「隠れクラス」が導入。

Java 16 (2021年3月)

  • JEP 394: Pattern Matching for instanceof
    パターンマッチングが正式に導入され、instanceofの使い勝手が向上。
  • JEP 395: Records
    recordクラスが標準機能に。
  • JEP 338: Vector API (Incubator)
    ベクトル操作を効率的に行うAPIがインキュベータモジュールとして追加。
  • JEP 376: ZGC: Concurrent Thread-Stack Processing
    ZGC(Z Garbage Collector)でスレッドスタックの同時処理が可能になり、パフォーマンスが向上。

Java 17 (2021年9月) – LTS (Long-Term Support)

  • JEP 409: Sealed Classes
    シールドクラスが正式に導入され、クラスの継承を制限する機能が利用可能に。
  • JEP 356: Enhanced Pseudo-Random Number Generators
    擬似乱数生成器(PRNG)が強化され、ランダム数の生成が柔軟に。
  • JEP 382: New macOS Rendering Pipeline
    macOS向けの新しいレンダリングパイプラインが追加され、UIの描画が改善。
  • JEP 406: Pattern Matching for switch (Preview)
    switch文にパターンマッチングが導入され、条件分岐がより柔軟に。

Java 18 (2022年3月)

  • JEP 413: Code Snippets in Java API Documentation
    JavaDocにコードスニペットを埋め込む機能が追加され、ドキュメントの可読性が向上。
  • JEP 408: Simple Web Server
    簡単なWebサーバーをJavaで実行できる機能が追加され、開発者向けのテストが容易に。
  • JEP 416: Reimplement Core Reflection with Method Handles
    コアリフレクションがメソッドハンドルを使って再実装され、パフォーマンスが改善。

Java 19 (2022年9月)

  • JEP 405: Record Patterns (Preview)
    recordのパターンマッチングがプレビューとして導入され、より簡潔なコードが記述可能に。
  • JEP 424: Foreign Function & Memory API (Preview)
    JNIの代替として、他言語関数やメモリ操作のためのAPIがプレビューとして追加。
  • JEP 422: Linux/RISC-V Port
    Linux/RISC-V向けのポートが追加され、Javaのプラットフォームサポートが拡充。

Java 20 (2023年3月)

  • JEP 429: Scoped Values (Incubator)
    スレッドローカルの代替となる、スコープ付きの値を扱うAPIがインキュベータモジュールとして導入。
  • JEP 432: Record Patterns (Second Preview)
    レコードパターンが第2のプレビューとして再導入され、さらなる改善が。
  • JEP 433: Pattern Matching for switch (Fourth Preview)
    switch文のパターンマッチングが第4のプレビューとして更新され、より強力な機能に。

Java 21 (2023年9月) – LTS

  • JEP 445: Unnamed Patterns and Variables (Preview)
    名前のないパターンと変数を扱う新しい構文がプレビューとして導入され、簡潔なコードが記述可能に。
  • JEP 441: Pattern Matching for switch
    パターンマッチングがswitch文の正式機能として導入され、柔軟な条件分岐が可能に。
  • JEP 430: String Templates (Preview)
    テンプレート文字列を簡単に扱うための構文がプレビューとして追加され、文字列操作が強化。

Java 22 (2024年3月予定)

  • JEP 453: Structured Concurrency (Preview)
    構造化された並行処理をサポートする新しいAPIがプレビューとして導入され、並行処理の管理が簡素化。
  • JEP 442: Foreign Function & Memory API (Third Preview)
    他言語との相互運用性を高めるためのAPIが第3のプレビューとして追加され、さらなる安定性と機能強化が。
  • JEP 452: Key Encapsulation Mechanism API
    鍵カプセル化メカニズム(KEM)のサポートが追加され、暗号化関連の操作が強化。

まとめ

Javaの各バージョンで導入されたAPIや機能の変更点を理解することは、最新のJavaを活用する上で非常に重要です。Java 12以降、さまざまな新機能や改善が行われており、これらを効果的に取り入れることで、開発効率とコードのパフォーマンスを向上させることができます。詳細については、Java New API since JDK 11 を参照してください。

Javaの進化を追いかけ、最新の技術をプロジェクトに取り入れましょう。