ホームページ  >  記事  >  Java  >  項目 ストリーム内で副作用のない関数を優先する

項目 ストリーム内で副作用のない関数を優先する

WBOY
WBOYオリジナル
2024-08-08 16:46:52663ブラウズ

Item  Dê preferência às funções sem efeitos colaterais nas streams

ストリームの使用方法の概要:

  • 新規ユーザーはストリーム パイプラインで計算を表現するのが難しいと感じるかもしれません。
  • ストリームは関数型プログラミングに基づいており、表現力、速度、並列化を実現します。

計算の構造:

  • 純粋関数を使用した一連の変換としての構造計算。
  • 純粋な関数は入力のみに依存し、状態は変更されません。

副作用:

  • ストリーム操作に渡される関数の副作用を回避します。
  • 外部状態を変更する forEach の不適切な使用は「悪臭」です。

例 1: 副作用のあるコード

Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {
    words.forEach(word -> {
        freq.merge(word.toLowerCase(), 1L, Long::sum);
    });
}

問題: このコードは、forEach を使用して外部状態 (freq) を変更します。これは反復的であり、ストリームを利用しません。

例 2: 副作用のないコード

Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
    freq = words.collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()));
}

解決策: Collectors.groupingBy コレクターを使用して、外部状態を変更せずに頻度テーブルを作成します。より短く、明確で、より効率的です。

ストリーム API の流用:

  • 反復ループを模倣するコードはストリームを利用しません。
  • より効率的で読みやすい操作を行うには、コレクターを使用します。

コレクター:

  • リストやセットなどのコレクションへの結果の収集を簡素化します。
  • Collectors.toList()、Collectors.toSet()、Collectors.toCollection(collectionFactory).

例 3: 最も頻繁に使用される 10 個の単語のリストを抽出する

List<String> topTen = freq.entrySet().stream()
    .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
    .limit(10)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

説明:

  • 周波数マップのエントリを値の降順に並べます。
  • ストリームを 10 ワードに制限します。
  • 最も頻繁に使用される単語をリストに収集します。

コレクター API の複雑さ:

  • API には 39 のメソッドがありますが、多くは高度な用途向けです。
  • コレクターを使用してマップ (toMap、groupingBy) を作成できます。

マップと収集戦略:

  • 一意の Key-Value の toMap(keyMapper, valueMapper)。
  • マージ機能を使用してキーの競合に対処する戦略。
  • groupingBy は、分類子関数に基づいて要素をカテゴリにグループ化します。

例 4: マージ関数で toMap を使用する

Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
    freq = words.collect(Collectors.toMap(
        String::toLowerCase, 
        word -> 1L, 
        Long::sum
    ));
}

説明:

  • toMap は単語をその頻度にマップします。
  • マージ関数 (Long::sum) は、頻度を合計することでキーの競合を処理します。

例 5: アーティストごとにアルバムをグループ化し、最も売れているアルバムを見つける

Map<Artist, Album> topAlbums = albums.stream()
    .collect(Collectors.toMap(
        Album::getArtist,
        Function.identity(),
        BinaryOperator.maxBy(Comparator.comparing(Album::sales))
    ));

説明:

  • toMap は、アーティストをベストセラーのアルバムにマッピングします。
  • BinaryOperator.maxBy は、各アーティストのベストセラー アルバムを決定します。

文字列コレクション:
Collectors.joining は、文字列をオプションの区切り文字で連結します。

例 6: 区切り文字を使用した文字列の連結

String result = Stream.of("came", "saw", "conquered")
    .collect(Collectors.joining(", ", "[", "]"));

説明:

  • Collectors.joining は、区切り文字、プレフィックス、サフィックスとしてカンマを使用して文字列を連結します。
  • 結果: [来た、見た、征服した]。

結論:

  • ストリームの本質は副作用のない関数にあります。
  • forEach は結果を報告するためにのみ使用してください。
  • ストリームを効果的に使用するには、コレクターに関する知識が不可欠です。

以上が項目 ストリーム内で副作用のない関数を優先するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。