Stream


Stream APIとは?

Java 8 부터 Collection interface에 추가된 기능으로, 데이터를 선언적으로 처리하고 멀티코어 아키텍처를 활용할 수 있도록 설계되었다.ここでの宣言的処理とは可読性に関係する.簡単に例を示します
// for-loop
public int example1(int[] numbers) {
	int max = 0;
    
	for (int i = 0 ; i < numbers.length) {
    	if (max >= numbers[i]) {
        	max = numbers[i];
        }
    }
    
    return max;
}

// stream
public int example2(int[] numbers) {
	return Arrays.stream(numbers)
    		.max()
            .getAsInt();
}
	
example1では、maxの値が更新された部分が比較値によって分かるため、動作手順を詳細に知ることができるが、可読性が劣る.
また、example1メソッドを実際に実行すると、if (max >= numbers[i])部分で誤った比較が行われたため、最大値ではなく最小値が返される.この部分はif (max < numbers[i])に変更します.
逆に,example2ではどのような動作過程を経るかは示されていないが,どのような動作をするかについては明確な規定がある.max()法により最大値が得られた.

特長


Stream APIには、次のような機能があります.
  • は、演算を最大限に遅延させる.
  • 青茶食と方法参照.
  • 使い捨て.
  • データソースは変更されません.
  • 1.演算をできるだけ遅らせる.최대한 연산을 지연한다とは、Streamの要素が実際に使用されるまで演算を行わないことを意味します.(=lazy evaluation)
    public void example3(List<String> names) {
    	names.stream()
        	.filter(e -> e.equals("Park")) // 연산 X
            .forEach(System.out::println); // 실제 연산 시작
    }
    注釈処理がexample3からforEach(System.out::println)の部分で行われると、実行速度はAからBに急減する.
    これは,filter()メソッドの後にフィルタリングされた要素が使用されていないため,演算がまったく行われないためである.
    public void example4(List<Product> productList) { // List size == 100000
      productList.stream()
        .filter(product -> {
          System.out.println(product.getName());
          return (product.getPrice() % 2 == 0);
        })
        .limit(5)
        .forEach(product -> product.setName("a")); // 의미 없는 종단 연산
    }
    出力結果
    // 각 라인은 Product의 name 필드, 총 8개
    yorvpjcyqepbxhaepntj
    rechjraadmxyzsljynla
    golfefamxtxcpritpkfa
    veanooelpbznqjkagmvs
    ihwetcmlmgyxciwlbcix
    nddbznzhcasgxldnvuhh
    jraurhufcnfbugmetvto
    fbpzxcwlrsrcmhoaygcb 
    example4は、lazy evaluationの利点をより明確に示している.
    filter(product -> {
    	System.out.println(product.getName());
        return (product.getPrice() % 2 == 0)
    }
    上記の関数の動作を直感的に考慮すると、100000個のProduct nameが出力される可能性がありますが、実際には8個のnameしか出力されません.
    limit(5)
    これは、上記のlimit(5)関数により、返すオブジェクトの数を最大5個に制限しているため、filterに条件に合致するオブジェクトが5個見つかれば、次の操作が可能となるからである.
    以上の結果では、8つの検索対象に5つのprice % 2 == 0があるため、出力結果には8つの製品名がある.
    2.ランダ式とメソッド参照を使用します.
    1)青茶式
    ランダ式を作る方法はいろいろあります.また、深く入ると함수형 인터페이스(functional interface)度を紹介する必要があるので、この投稿で簡単に紹介し、その後新しい記事で詳しく紹介します.
    // e -> equals("Park")
    function isPark(String e) {
        return e.equals("Park");
    }
    예제 3からe -> equals("Park")は、以下に示すように一般的な関数形式に変換される.eはパラメータ、equals("Park")は戻り値です.ラムダ式で関数を1つずつ書く必要がなく,利便性が向上した.
    2)方法の参考
    ラムダ式では,パリミットを直接関数に渡すだけでは表現を簡略化するために導入された機能である.
    // 파일을 삭제하는 메소드
    public void example5(List<String> filePathList) {
    	filePathList.stream()
        			.map(File::new)
                    .forEach(file -> file.delete());
    }
    上記の예제 5からFile::newの部分が方法の参考です.  map関数では、filePathListに格納されたファイルのパスをnew File(String filePath)に渡すだけで、この構文はFile::newに短縮される.
    3.使い捨て
    public void example6(List<String> filePathList) {
    	Stream<String> filePathStream = filePathList.stream();
        
        // 파일 삭제
        filePathStream.map(File::new)
        			  .forEach(file -> file.delete());
                  
        // 파일 생성
        filePathStream.forEach(File::new); // runtime 오류 발생
    }
    出力結果
    Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    ...
    예제 6のように、使用済みストリームを再使用すると、ランタイムエラーが発生します.( stream has already been operated upon or closed )
    この部分は注意して使用してください.△実際、変数として宣言するのは難しいので、再使用する必要はありません.
    4.データ・ソースは変更されません.
    public void example6(List<String> arr) {
    	List<String> arr = new ArrayList<>();
    
        arr.add("d");
        arr.add("a");
        arr.add("c");
        arr.add("q");
        arr.add("v");
    
        arr.stream()
            .sorted()
            .collect(Collectors.toList()); //a, c, d, q, v
            
        for (String element : arr) {
            System.out.println(element);
        }
    }
    出力結果
    d
    a
    c
    q
    v // 정렬 되지 않음
    public void example7(List<Product> productList) {
    	// Product의 name을 "s"로 변경
    	productList.stream()
        		   .forEach(product -> product.setName("s");
                   
        for (Product product : productList) {
        	System.out.println(product.getName());
        }
    }
    出力結果
    s
    s
    s
    ... // name이 "s"로 변경됨
    List<String>を使用した예제 6ではソートできませんが、List<Product>を使用した예제 7では、データ・ソースが変化していることがわかります.Javaでは、オブジェクトを関数パラメータに渡すと、オブジェクトのアドレス値がコピーされるため、フィールドの値は実際のオブジェクトインスタンスを参照することによって変更されます.
    オブジェクトを扱うときは、その点に注意すればよい.しかし、これまでの使用状況から見ると、この点は実際の利益よりも大きいようだ.

    終了時..。


    今回の投稿では、Stream APIについて説明します.私は初めてある概念についての総括的な文章を書いたが、読む人を考えると、書くのは難しいようだ.
    しかし、私のブログに書いた文章が他の人に役に立つことを望んで、これからも努力して書きます.
    気になるところ間違っているところをコメントで指摘すると確認して修正します長いコメントありがとうございます