Javaシリーズ(1):Java 8の新しいプロパティStreamの詳細


JDK 8新特性:stream詳細

  • 1基本特性
  • 1.1ストリームの特性
  • 1.2 Stream
  • を作成する
  • 2ストリームAPI詳細
  • 2.1 BaseStream詳細
  • 2.2 Stream詳細
  • 3一般的な方法
  • 3.1プレゼンテーションに使用するデータ
  • 3.2フィルタリングとマッチング
  • 3.3重合
  • 3.3.1 max、min、count
  • 3.3.2削減(reduce)
  • 3.3.3収集(collect)
  • 3.4マッピング(map)
  • 3.5ソート(sorted)
  • 3.6抽出ストリームおよび組合せストリーム
  • 1基本特性


    Java 8のAPIには、ストリーム、すなわちstreamという新しいプロパティが追加されています.streamは、配列または集合の要素をストリームと見なし、パイプ内を流れるときにデータをフィルタ、ソート、その他の操作を行います.

    1.1流れの特性


    1、streamはデータを格納せず、特定のルールに従ってデータを計算し、一般的に結果を出力する.2、streamはデータソースを変更せず、通常は新しいセットが生成されます.3、streamは遅延実行特性を有し、端末操作を呼び出す場合にのみ中間操作が実行される.4、stream操作には端末操作と中間操作がありますが、この2つはそれぞれ何を表していますか.端末操作:ストリームが消費され、この操作は結果を生み出し、ストリームが消費された場合、再利用できません.≪中間操作|Intermediate Operations|Emdb≫:中間操作によって別のストリームが生成されます.したがって、中間操作は、一連の動作を実行するパイプを作成するために使用することができる.特に注意しなければならない点は、中間操作がすぐに発生しないことです.逆に、中間操作で作成された新しいストリーム上で端末操作が実行されると、中間操作で指定された操作が発生します.従って、中間動作は遅延して発生し、中間動作の遅延挙動は主にストリームAPIがより効率的に実行できるようにする.5、streamは多重化できず、端末操作を行ったストリームを再び呼び出すと、異常が放出される.

    1.2 Streamの作成


    配列によるストリームの作成
    public static void main(String[] args) {
    	//1.  Arrays.stream
    	//1.1    
    	int[] arr = new int[]{1,2,34,5};
        IntStream intStream = Arrays.stream(arr);
        //1.2    
        Student[] studentArr = new Student[]{new Student("s1",29),new Student("s2",27)};
        Stream<Student> studentStream = Arrays.stream(studentArr);
        //2.  Stream.of
        Stream<Integer> stream1 = Stream.of(1,2,34,5,65);
        //      int[]  
        Stream<int[]> stream2 = Stream.of(arr,arr);
        stream2.forEach(System.out::println);
    }
    

    コレクションによるフローの作成
    public static void main(String[] args) {
        List<String> strs = Arrays.asList("11212","dfd","2323","dfhgf");
        //     
        Stream<String> stream  = strs.stream();
        //     
        Stream<String> stream1 = strs.parallelStream();
    }
    

    2ストリームAPIの詳細


    BaseStreamは最も基本的なインタフェースであり、ストリームの基本的な機能を提供しています.

    2.1 BaseStreamの詳細


    BaseStreamインタフェースのソースコードは次のとおりです.
    public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
         Iterator<T> iterator();
         Spliterator<T> spliterator();
         boolean isParallel();
         S sequential();
         S parallel();
         S unordered();
         S onClose(Runnable closeHandler);
         @Override
         void close();
    }
    

    方法の詳細:
    シーケンス番号
    方法
    説明
    1
    Iterator iterator();
    ストリームの反復を取得し、その反復への参照を返します(ターミナル操作)
    2
    Spliterator spliterator();
    ストリームのspliteratorを取得し、その参照(端末操作)を返します.
    3
    boolean isParallel();
    呼び出しストリームがパラレルストリームである場合、trueが返されます.呼び出しストリームがシーケンスストリームである場合falseが返されます
    4
    S sequential();
    呼び出しストリームに基づいて、シーケンスストリームが返されます.呼び出しストリームがシーケンスストリームである場合、ストリームが返されます(中間操作)
    5
    S parallel();
    呼び出しストリームに基づいて、パラレルストリームが返されます.呼び出しストリームがパラレルストリームである場合、そのストリームが返されます(中間操作)
    6
    S unordered();
    呼び出しストリームに基づいて、無秩序なストリームが返されます.呼び出しストリームがすでに無秩序なストリームである場合、ストリームが返されます(中間操作)
    7
    S onClose(Runnable closeHandler);
    呼び出しストリームに基づいて、パラレルストリームが返されます.呼び出しストリームがパラレルストリームである場合、そのストリームが返されます(中間操作)
    8
    void close();
    AutoCloseableから継承された、登録クローズハンドラを呼び出し、呼び出しフローを閉じる(使用されることは少ない)

    2.2 Stream詳細


    Streamインタフェースのソースコードは次のとおりです.
    public interface Stream<T> extends BaseStream<T, Stream<T>> {
        Stream<T> filter(Predicate<? super T> predicate);
        <R> Stream<R> map(Function<? super T, ? extends R> mapper);
        IntStream mapToInt(ToIntFunction<? super T> mapper);
        LongStream mapToLong(ToLongFunction<? super T> mapper);
        DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
        <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
        IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
        LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
        DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
        Stream<T> distinct();
        Stream<T> sorted();
        Stream<T> sorted(Comparator<? super T> comparator);
        Stream<T> peek(Consumer<? super T> action);
        Stream<T> limit(long maxSize);
        Stream<T> skip(long n);
        void forEach(Consumer<? super T> action);
        void forEachOrdered(Consumer<? super T> action);
        Object[] toArray();
        <A> A[] toArray(IntFunction<A[]> generator);
        T reduce(T identity, BinaryOperator<T> accumulator);
        Optional<T> reduce(BinaryOperator<T> accumulator);
        <U> U reduce(U identity,
                     BiFunction<U, ? super T, U> accumulator,
                     BinaryOperator<U> combiner);
        <R> R collect(Supplier<R> supplier,
                      BiConsumer<R, ? super T> accumulator,
                      BiConsumer<R, R> combiner);
        <R, A> R collect(Collector<? super T, A, R> collector);
        Optional<T> min(Comparator<? super T> comparator);
        Optional<T> max(Comparator<? super T> comparator);
        long count();
        boolean anyMatch(Predicate<? super T> predicate);
        boolean allMatch(Predicate<? super T> predicate);
        boolean noneMatch(Predicate<? super T> predicate);
        Optional<T> findFirst();
        Optional<T> findAny();
    
        // Static factories
        public static<T> Builder<T> builder() {
            return new Streams.StreamBuilderImpl<>();
        }
    
    
        public static<T> Stream<T> empty() {
            return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false);
        }
    
    
        public static<T> Stream<T> of(T t) {
            return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
        }
    
    
        @SafeVarargs
        @SuppressWarnings("varargs") // Creating a stream from an array is safe
        public static<T> Stream<T> of(T... values) {
            return Arrays.stream(values);
        }
    
    
        public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
            Objects.requireNonNull(f);
            final Iterator<T> iterator = new Iterator<T>() {
                @SuppressWarnings("unchecked")
                T t = (T) Streams.NONE;
    
                @Override
                public boolean hasNext() {
                    return true;
                }
    
                @Override
                public T next() {
                    return t = (t == Streams.NONE) ? seed : f.apply(t);
                }
            };
            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                    iterator,
                    Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
        }
    
    
        public static<T> Stream<T> generate(Supplier<T> s) {
            Objects.requireNonNull(s);
            return StreamSupport.stream(
                    new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
        }
    
    
        public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
            Objects.requireNonNull(a);
            Objects.requireNonNull(b);
    
            @SuppressWarnings("unchecked")
            Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                    (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
            Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
            return stream.onClose(Streams.composedClose(a, b));
        }
    }
    

    上記のいくつかの重要な方法について説明します.
    シーケンス番号
    方法
    説明
    1
    Stream filter(Predicate super T> predicate);
    呼び出しストリームでpredicateで指定された述語要素を満たす新しいストリームを生成します(中間操作)
    2
    Stream map(Function super T, ? extends R> mapper);
    呼び出しストリームの要素にmapperを適用し、これらの要素を含む新しいストリームを生成します(中間操作)
    3
    IntStream mapToInt(ToIntFunction super T> mapper);
    呼び出しストリームの要素にmapperを適用し、これらの要素を含む新しいIntStreamストリームを生成します(中間操作)
    4
    Stream sorted();
    自然に並べ替えられた新しいストリームを生成(中間操作)
    5
    Stream sorted(Comparator super T> comparator);
    指定した条件からソートされた新しいストリームを生成します(中間操作)
    6
    void forEach(Consumer super T> action);
    ストリーム内の要素を巡回(終端操作)
    7
    void forEachOrdered(Consumer super T> action);
    ストリーム内の要素を巡回(終端操作)
    8
    Optional min(Comparator super T> comparator)
    デフォルトまたはカスタムのコンパレータを使用して、ストリームの最小値を取得します.
    9
    Optional max(Comparator super T> comparator)
    デフォルトまたはカスタムのコンパレータを使用して、ストリームの最大値を取得します.

    3一般的な方法


    3.1プレゼンテーションに使用するデータ


    次のプレゼンテーションデータとしてPersonエンティティクラスを作成します.Personにはnameとsalaryの2つのプロパティがあります.
    public class Person {
    	private String name;
    	private int salary;
    
    	//     
    	public Person(String name, int salary) {
    		this.name = name;
    		this.salary = salary;
    	 }
    	//   get set  
    }
    public class MyTest {
    	public static void main(String[] args) {
    		List<Person> personList= new ArrayList<Person>();
    		persons.add(new Person("Tom", 8900));
    		persons.add(new Person("Jack", 7000));
    		persons.add(new Person("Lily", 9000));
    	}
    }
    

    3.2フィルタリングと照合


    ストリームのフィルタリング、すなわちfilterは、ストリーム内の要素を一定の規則に従って検証し、条件に合致する要素を抽出する操作である.filterは通常collect(収集)と協力して、フィルタ結果を新しい集合に収集します.ストリームのマッチングは、フィルタリングと同様にルールに従って要素を抽出します.異なり、マッチングは単一の要素または単一の結果を返します.標準型フィルタ
    public static void main(String[] args) {
    	List<Integer> intList = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
    	List<Integer> collect = intList.stream().filter(x -> x > 7).collect(Collectors.toList());
    	System.out.println(collect);
    }
    //     :
    [8,9]
    

    参照タイプフィルタ
    public static void main(String[] args) {
    	List<Person> collect = personList.stream().filter(x -> x.getSalary() > 8000).collect(Collectors.toList());
    //     :           
    }
    

    マッチ
    public static void main(String[] args) {
    	List<Integer> list = Arrays.asList(7,6,9,3,8,2,1);
    
    	//      
    	Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
    	//     (      )
    	Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
    	//     
    	boolean anyMatch = list.stream().anyMatch(x -> x < 6);
    	System.out.println(findFirst);
    	System.out.println(findAny);
    	System.out.println(anyMatch);
    	}
    }
    //     :
    // 1、Optional[7]
    // 2、     ,     
    // 3、true
    

    3.3重合


    streamでは,ストリームに対して計算を行った結果,例えば和を求める,最値を求めるなど,このような操作を集約操作と呼ぶ.集約操作は一般化的にmax,min,countなどの方法とreduce,collectを含む.

    3.3.1 max、min、count


    1、String集合の中で最も長い要素を取得する
    public static void main(String[] args) {
    	List<String> list = Arrays.asList("adnm","admmt","pot");
    
    	Optional<String> max = list.stream().max(Comparator.comparing(String::length));
    	System.out.println(max);
    }
    
    //     :
    Optional[admmt]
    

    2.Integerコレクションの最大値を取得する
    public static void main(String[] args) {
    	List<Integer> list = Arrays.asList(7,6,9);
    
    	Optional<Integer> reduce = list.stream().max(new Comparator<Integer>() {
    		@Override
    		public int compare(Integer o1, Integer o2) {
    	    	return o1.compareTo(o2);
    		}
    	});
    	System.out.println(reduce);
    }
    //    :
    Optional[9]
    

    3、対象集合の最値(Personはプレゼンテーションデータを参照)
    public static void main(String[] args) {
    	list.add(new Person("a", 4));
    	list.add(new Person("b", 4));
    	list.add(new Person("c", 6));
    
    	Optional<Person> max = list.stream().max(Comparator.comparingInt(Person::getSalary));
    	System.out.println(max.get().getSalary());
    }
    //     :6,    max  min  
    

    4、count
    public static void main(String[] args) {
    	List<Integer> list = Arrays.asList(7,6,9);
    
    	long count = list.stream().filter(x -> x > 6).count();
    	System.out.println(count);
    }
    //     :2
    

    3.3.2削減(reduce)


    名前の通り、縮小操作は、1つのストリームを1つの値に縮小することであり、例えば、1つの集合に対して和を求め、積を求めるなどである.Streamストリームは3つのreduceを定義します.
    public interface Stream<T> extends BaseStream<T, Stream<T>> {
    	//   1
    	T reduce(T identity, BinaryOperator<T> accumulator);
    	//   2
    	Optional<T> reduce(BinaryOperator<T> accumulator);
    	//   3
    	<U> U reduce(U identity,
              BiFunction<U, ? super T, U> accumulator,
              BinaryOperator<U> combiner);
    }
    

    最初の2つの削減方法:最初の削減方法は、BinaryOperator accumulator function(二元累積計算関数)とidentity(表示値)をパラメータとして受信し、戻り値はTタイプ(ストリーム内の要素タイプを表す)のオブジェクトです.accumulatorは、2つの値を操作して結果を得る関数を表します.identityはaccumulator関数の規則に従って計算に参加し、もし関数が求和演算であれば、関数の求和結果にidentityを加えると最終結果であり、関数が求積演算であれば、関数結果にidentityを乗じると最終結果である.2つ目の削減方法の違いは、identityがなく、戻り値がOptional(JDK 8の新しいクラスでnullを格納できる)であることです.次の例では、前の2つのreduceの使用方法を示します.通常の集合の合計、最大値の合計
    public static void main(String[] args) throws Exception {
    	 List<Integer> list = Arrays.asList(1, 3, 2);
    	 //   
    	 Integer sum = list.stream().reduce(1, (x, y) -> x + y);
    	 //    7,   list       1
    	 System.out.println(sum);
    	 //   2
    	 Integer sum2 = list.stream().reduce(1, Integer::sum);
    	 System.out.println(sum2);  //   :7
    
    	 //    
    	 Integer max = list.stream().reduce(6, (x, y) -> x > y ? x : y);
    	 System.out.println(max);  //   :6
    	 //   2
    	 Integer max2 = list.stream().reduce(1, Integer::max);
    	 System.out.println(max2); //   :3
    }
    

    対象集合の合計、最大値の合計:
    public class MyTest {
    	public static void main(String[] args) {
    		List<Person> personList = new ArrayList<Person>();
    		personList.add(new Person("Tom", 8900));
    		personList.add(new Person("Jack", 7000));
    		personList.add(new Person("Lily", 9000));
    		
    		//   
    		//     :Optional[24900]
    		System.out.println(personList.stream().map(Person::getSalary).reduce(Integer::sum));
    
    		//    -  1
    		Person person = personList.stream().reduce((p1, p2) -> p1.getSalary() > p2.getSalary() ? p1 : p2).get();
    		//     :Lily:9000
    		System.out.println(person.getName() + ":" + person.getSalary());
    		//    -  2
    		//     :Optional[9000]
    		System.out.println(personList.stream().map(Person::getSalary).reduce(Integer::max));
    		//    -  3:
    		System.out.println(personList.stream().max(Comparator.comparingInt(Person::getSalary)).get().getSalary());
    	}
    }
    

    3番目の削減操作3番目の削減操作は、表示値(identity)、2元操作アキュムレータ(BiFunction accumulator)、2元組合せ方法(BinaryOperator<.u>combiner)の3つのパラメータを受信します.ここでcombinerは、パラレルの下でオブジェクトのセットで最大値を求めるインスタンスのみを使用して、第3の削減操作の使用方法を実証します.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	//   -  1
    	Integer sumSalary = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(),
    				(sum1, sum2) -> sum1 + sum2);
    	System.out.println(sumSalary);  // 24900
    	//   -  2
    	Integer sumSalary2 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
    	System.out.println(sumSalary2);  // 24900
    
    	//     -  1
    	Integer maxSalary = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),Integer::max);
    	System.out.println(maxSalary);  // 9000
    	//     -  2
    	Integer maxSalary2 = personList.stream().reduce((max, p) -> max > p.getSalary() ? max : p.getSalary(),(max1, max2) -> max1 > max2 ? max1 : max2);
    	System.out.println(maxSalary2);  // 9000
    }
    

    次に、combinerがシリアルストリームでは機能せず、パラレルストリームで機能していることを確認します.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	//   combiner-   
    	Integer sumSalary = personList.stream().reduce(0, (sum, p) -> {
    		System.out.format("accumulator: sum=%s; person=%s
    "
    , sum, p.getName()); return sum += p.getSalary(); } , (sum1, sum2) -> { System.out.format("combiner: sum1=%s; sum2=%s
    "
    , sum1, sum2); return sum1 + sum2; }); System.out.println(" :" + sumSalary); // : // accumulator: sum=0; person=Tom // accumulator: sum=8900; person=Jack // accumulator: sum=15900; person=Lily // :24900 // combiner- Integer sumSalary2 = personList.parallelStream().reduce(0, (sum, p) -> { System.out.format("accumulator: sum=%s; person=%s
    "
    , sum, p.getName()); return sum += p.getSalary(); } , (sum1, sum2) -> { System.out.format("combiner: sum1=%s; sum2=%s
    "
    , sum1, sum2); return sum1 + sum2; }); System.out.println(" :" + sumSalary2); // : // accumulator: sum=0; person=Jack // accumulator: sum=0; person=Tom // accumulator: sum=0; person=Lily // combiner: sum1=7000; sum2=9000 // combiner: sum1=8900; sum2=16000 // :24900 }

    以上の出力結果から,パラレルストリームではcombinerメソッドが呼び出され,パラレルアキュムレータでそれぞれ得られた結果を組み合わせて最終結果が得られる.

    3.3.3収集(collect)


    collect操作は様々な方法をパラメータとして受け入れ,ストリーム中の要素を集約し,得られる.
    public interface Stream<T> extends BaseStream<T, Stream<T>> {
    	<R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,
                      BiConsumer<R, R> combiner);
        <R, A> R collect(Collector<? super T, A, R> collector);
    }
    

    上記のインタフェース定義を見ると、collectorはパラメータとしてCollectorを使用し、Collectorはsupplier(初期コンストラクタ)、accumulator(アキュムレータ)、combiner(コンビネーション)、finisher(ターミネータ)の4つの異なる操作を含むことがわかります.実際、Collectorsクラスには多くの収集操作が内蔵されています.1、averagingシリーズaveragingDouble、averagingInt、averagingLongの3つの方法の処理過程は同じで、streamの平均値を返しますが、結果を返すタイプが違います.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	Double averageSalary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
    	System.out.println(averageSalary);  //   :8300
    }
    

    2、summarizingシリーズsummarizingDouble、summarizingInt、summarizingLongの3つの方法はstreamの統計結果mapを返すことができ、異なる点も結果mapのvalueタイプが異なり、それぞれdouble、int、longタイプである.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
    	System.out.println(collect);
    	//     :
    	// DoubleSummaryStatistics{count=3, sum=24900.000000, min=7000.000000, average=8300.000000, max=9000.000000}
    }
    

    3、joining joiningはstreamの要素を特定のコネクタ(なければ直接接続)で文字列に接続することができます.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
    	System.out.println(names);
    }
    

    4、reduce Collectorsにはreduceが内蔵されており、次の例のようにカスタム契約を完了できます.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	Integer sumSalary = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> i + j));
    	System.out.println(sumSalary);  //   :24900
    	
    	Optional<Integer> sumSalary2 = list.stream().map(Person::getSalary).reduce(Integer::sum);
    	System.out.println(sumSalary2);  // Optional[24900]
    }
    

    5、groupingBy groupingByメソッドは、mysqlのgroupBy文のようにstreamの要素をルールに従ってグループ化することができます.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    
    	//     
    	Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getName));
    	System.out.println(group);
    	//     :{Tom=[mutest.Person@7cca494b],
    	// Jack=[mutest.Person@7ba4f24f],Lily=[mutest.Person@3b9a45b3]}
    
    	//     :  name  ,  salary  :
    	Map<String, Map<Integer, List<Person>>> group2 = personList.stream()
    				.collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getSalary)));
    	System.out.println(group2);
    	//     :{Tom={8900=[mutest.Person@7cca494b]},Jack={7000=[mutest.Person@7ba4f24f]},Lily={9000=[mutest.Person@3b9a45b3]}}
    }
    

    6、toList、toSet、toMap Collectorsに内蔵されたtoListなどの方法はstream中の要素を所望の集合に簡単に集めることができ、非常によく使われる機能であり、通常はfilter、mapなどの方法に合わせて使用される.
    public static void main(String[] args) {
    	List<Person> personList = new ArrayList<Person>();
    	personList.add(new Person("Tom", 8900));
    	personList.add(new Person("Jack", 7000));
    	personList.add(new Person("Lily", 9000));
    	personList.add(new Person("Lily", 5000));
    
    	// toList
    	List<String> names = personList.stream().map(Person::getName).collect(Collectors.toList());
    	System.out.println(names);
    
    	// toSet
    	Set<String> names2 = personList.stream().map(Person::getName).collect(Collectors.toSet());
    	System.out.println(names2);
    
    	// toMap
    	Map<String, Person> personMap = personList.stream().collect(Collectors.toMap(Person::getName, p -> p));
    	System.out.println(personMap);
    }
    

    3.4マッピング(map)


    Streamストリームでは、mapは1つのストリームの要素を一定のマッピング規則に従って別のストリームにマッピングすることができる.1、データ>>データ
    public static void main(String[] args) {
    	String[] strArr = { "abcd", "bcdd", "defde", "ftr" };
    	Arrays.stream(strArr).map(x -> x.toUpperCase()).forEach(System.out::println);
    }
    //     :
    ABCD  BCDD  DEFDE  FTR
    

    2、対象集合>>データ
    public static void main(String[] args) {
    	//      ,personList         personList
    	personList.stream().map(person -> person.getSalary()).forEach(System.out::println);
    }
    //     :
    ABCD  BCDD  DEFDE  FTR
    

    3、対象集合>>対象集合
    public static void main(String[] args) {
    	//      ,personList         personList
    	List<Person> collect = personList.stream().map(person -> {
    	  	person.setName(person.getName());
    	  	person.setSalary(person.getSalary() + 10000);
    	  	return person;
    	}).collect(Collectors.toList());
    	System.out.println(collect.get(0).getSalary());
    	System.out.println(personList.get(0).getSalary());
    
    	List<Person> collect2 = personList.stream().map(person -> {
    	  	Person personNew = new Person(null, 0);
    	  	personNew.setName(person.getName());
    	 	personNew.setSalary(person.getSalary() + 10000);
    	  	return personNew;
    	 }).collect(Collectors.toList());
    	 System.out.println(collect2.get(0).getSalary());
    	 System.out.println(personList.get(0).getSalary());
    }
    //     :
    // 1、18900   18900,            personList。
    // 2、18900   8900,            personList。
    

    3.5ソート(sorted)


    Sorted法は対流を並べ替え,中間操作である新しいstream流を得た.Sortedメソッドでは、自然ソートまたは特定の比較器を使用できます.ナチュラルソート
    public static void main(String[] args) {
    	String[] strArr = { "abc", "m", "M", "bcd" };
    	System.out.println(Arrays.stream(strArr).sorted().collect(Collectors.toList()));
    }
    //     :
    [M, abc, bcd, m]
    

    カスタムソート
    public static void main(String[] args) {
    	String[] strArr = { "ab", "bcdd", "defde", "ftr" };
    	// 1、       ,       
    	Arrays.stream(strArr).sorted(Comparator.comparing(String::length)).forEach(System.out::println);
    	// 2、     ,       
    	Arrays.stream(strArr).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
    	// 3、     
    	Arrays.stream(strArr).sorted(Comparator.reverseOrder()).forEach(System.out::println);
    	// 4、       
    	Arrays.stream(strArr).sorted(Comparator.naturalOrder()).forEach(System.out::println);
    }
    /**
     * thenComparing
     *         
     *     String     
     */
    @Test
    public void testSorted3_(){
    	Arrays.stream(arr1).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEa	
    	ch(System.out::println);
    }
    public char com1(String x){
        return x.charAt(0);
    }
    //     :
    // 1、ftr  bcdd  defde
    // 2、defde  bcdd  ftr  ab
    // 3、ftr  defde  bcdd  ab
    // 4、ab  bcdd  defde  ftr
    

    3.6抽出フローと組合せフロー

    public static void main(String[] args) {
    	String[] arr1 = {"a","b","c","d"};
        String[] arr2 = {"d","e","f","g"};
        String[] arr3 = {"i","j","k","l"};
    		
    	/**
         *      stream     stream(   stream      ),      
         *     :a b c d e(     ,      )
         */
    	Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        Stream.concat(stream1,stream2).distinct().forEach(System.out::println);
        	
        /**
         * limit,        n   
         *     :1 3 5 7 9 11 13 15 17 19 
         */ 
         Stream.iterate(1,x->x+2).limit(10).forEach(System.out::println);
       
       	/**
         * skip,   n   
         *     :3 5 7 9 11 
         */			
    	Stream.iterate(1,x->x+2).skip(1).limit(5).forEach(System.out::println);
    }