Javaのストリームストリームの簡単な使用

コンテンツ

ストリームAPIとは

 StreamAPIを使用する理由

ストリーム操作の3つのステップ

ストリームウェイを作成する

ストリームの作成方法1:コレクションを介して

ストリームメソッド2の作成:アレイ経由

 ストリームを作成する3番目の方法:ストリームのof()を使用する

ストリームの作成方法4:無限のストリームを作成する

ストリームの中間操作

1-スクリーニングとスライス

2-マップ

3-並べ替え

ストリームの操作を終了します

 ターミナル操作は、ストリームのパイプラインから結果を生成します。結果は、ストリームではない任意の値になります。たとえば、List、Integer、さらにはvoidです。ストリームが終了した後は、再度使用することはできません

1-一致して検索 

2-削減

3-収集

オプションクラス

 オプションクラスのオブジェクトを作成するメソッド

オプションのコンテナにオブジェクトが含まれているかどうかを確認します。

 オプションコンテナのオブジェクトを取得します。


ストリームAPIとは

 Streamは、Java 8でコレクションを操作するための重要な抽象概念です。Streamは、コレクション
に対して実行する操作を指定でき、データの検索、フィルタリング、マッピングなどの非常に複雑な操作を実行できます。Stream APIを使用し
てコレクションデータを操作することは、SQLを使用してデータベースクエリを実行することに似ています。
Stream APIを使用して、操作を並行して実行することもできます。つまり、Stream APIは、
データを処理するための効率的で使いやすい方法を提供します

 StreamAPIを使用する理由

実際の開発では、プロジェクトのほとんどのデータソースはMysql、Oracleなどからのものです。しかし、今では
MongDB、Radisなどのデータソースが増えており、これらのNoSQLデータ
はJavaレベルで処理する必要があります。
StreamとCollectionの違い:Collectionは静的なメモリ内データ
構造ですが、Streamは計算に関するものです。前者は主にメモリに向けられてメモリに格納され、
後者は主にCPUに向けられており、計算はCPUを介して実現されます。

  •  ストリームとは正確には何ですか?
  • データソース(コレクション、配列など)によって生成された要素のシーケンスを操作するために使用されるデータチャネルです。
  • 「コレクションはデータに関するものであり、ストリームは計算に関するものです!」
  • ①ストリーム自体は要素を格納しません。
    ②Streamはソースオブジェクトを変更しません。代わりに、結果を保持する新しいストリームを返します。
    ③ストリーム操作は怠惰に実行されます。これは、実行する前に結果が必要になるまで待機することを意味します。

ストリーム操作の3つのステップ

  1.         データソース(コレクション、配列など)の ストリームを作成し、ストリームを取得します
  2. 中間操作               データソースのデータを処理するための中間操作チェーン
  3.  終了操作(終了操作)               終了操作が実行されると、中間操作のチェーンが実行され、結果が生成されます。その後、二度と使用されません

ストリームウェイを作成する

ストリームの作成方法1:コレクションを介して

Java8のCollectionインターフェースが拡張され、ストリームを取得するための2つのメソッドが提供されます。
 デフォルトStream <E> stream():順次ストリームを返します
 デフォルトStream <E> parallelStream():並列ストリームを返します

例:

//1.可以通过Collection系列集合提供的stream()或parallelStream()
        List<String> list=new ArrayList<>();
        Stream<String> stream1=list.stream();

ストリームメソッド2の作成:アレイ経由

Java8の配列の静的メソッドstream()は、配列ストリームを取得できます。static <T> Stream <T> stream(T [] array):ストリームを返します
 

対応するプリミティブ型の配列を処理できるオーバーロードされたフォーム:
 public static IntStream stream(int [] array)
 public static LongStream stream(long [] array)
 public static DoubleStream stream(double [] array)

  //2.通过Arrays中的静态方法stream()获取数组流
        Employee[] emps=new Employee[10];
        Stream<Employee> stream2=Arrays.stream(emps);
        stream2.forEach((m)->System.out.println("m="+m));

ストリームを 作成する3番目の方法:ストリームのof()を使用します

Streamクラスの静的メソッドof()を呼び出して、値を表示することでストリームを作成できます。任意の数の引数を受け取ることができます。
public static <T> Stream <T> of(T ... values):ストリームを返します

 例

  //3.通过Stream类中的静态方法of()
        Stream<String> stream3=Stream.of("aa","bb","cc");
        stream3.forEach(System.out::println);

ストリームの作成方法4無限のストリームを作成する

無限ストリームは、静的メソッドStream.iterate()およびStream.generate()を使用して作成できますpublic static <T> Stream <T> iterate(final T seed、final UnaryOperator <T> f)
反復して、 public static <T> Stream <T> generate(Supplier <T> s)を生成します。


 //4.创建无限流
        //迭代
        Stream<Integer> stream4=Stream.iterate(0,(x) -> x+2);
        stream4.limit(10).forEach(System.out::println);

        //生成
        Stream.generate( ()->Math.random())
                .limit(5)
                .forEach(System.out::println);

ストリームの中間操作

複数の中間操作を接続してパイプラインを形成できます。パイプラインで終了
操作がトリガーされない限り、中間操作は処理を実行しません。操作が終了すると
、一気に処理される「遅延評価」と呼ばれます。

1-スクリーニングとスライス

 方法  描 述
filter(述語p) ストリームから特定の要素を除外するLambdaを受信します
明確() フィルタリングし、ストリームによって生成された要素のhashCode()およびequals()によって重複要素を削除します
limit(long maxSize) 指定された要素数を超えないようにストリームを切り捨てます
skip(long n) 要素をスキップし、最初のn個の要素が破棄されたストリームを返します。ストリーム内の要素がn未満の場合
、空のストリームが返されます。limit(n)を補完する

例:

最初にエンティティクラスを作成します

package com.chen;

import com.sun.org.apache.xerces.internal.util.Status;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private int id;
    private String name;
    private int age;
    private double salary;
    private Status status;


    public Employee(int id){
        this.id=id;
    }
    public Employee(int id,int age){
        this.id=id;
        this.age=age;
    }

//    public Employee(int id, String name, int age, double salary,Status status) {
//        this.id=id;
//        this.name=name;
//        this.age=age;
//        this.salary=salary;
//        this.status=status;
//    }

    public Employee(int id, String name, int age, double salary) {
        this.id=id;
        this.name=name;
        this.age=age;
        this.salary=salary;

    }

    public enum Status{
        FREE,
        BUSY,
        VOCATION;

    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", status=" + status +
                '}';
    }
}

コード

package com.chen.stream;


import com.chen.Employee;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

/*
 *
 *
 * 一.Stream 的三个操作步骤:
 *
 * 1.创建Stream
 * 2.中间操作
 * 3.终止操作(终端操作)
 *
 *
 *
 *
 **/
public class TestStreamAPI2 {


    List<Employee> employees = Arrays.asList(
            new Employee(1,"张三1", 18, 9999.99),
            new Employee(1,"张三2", 48, 6999.99),
            new Employee(1,"张三3", 58, 1999.99),
            new Employee(1,"张三4", 28, 5999.99),
            new Employee(1,"张三4", 28, 5999.99)
    );


    /*
    *
    * 筛选与切片
    * filter——接收Lambda,从流中排除某些元素
    * limit——截断流,使其元素不超过给定数量
    * skip(n)——跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流。与limit(n)互补
    * distinct——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
    *
    **/

    //内部迭代:迭代操作由Stream API完成
    @Test
    public void test1(){
        //中间操作
        Stream<Employee> stream= employees.stream()
                .filter(((e)->e.getAge()>35));
        System.out.println("xkkkk"+stream);

        //终止操作
        stream.forEach(System.out::println);

        //中间操作
        Stream<Employee> stream2= employees.stream()
                .filter(((e)->{
                    System.out.println("Stream API 的中间操作");
                    return  e.getAge()>35;
                }));
        //终止操作:一次性执行全部内容,即为“惰性求值"
        stream2.forEach(System.out::println);

    }


   //外部迭代
    @Test
    public void test2(){
        Iterator<Employee> iterator=employees.iterator();
        while ((iterator.hasNext())){
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test3(){

        employees.stream()
                .filter((e) -> {
                    System.out.println("短路!");
                   return e.getSalary()>5000;
                })
                .limit(2)
                 .forEach(System.out::println);

    }

    @Test
    public  void test4(){
        employees.stream()
                .filter((e) -> e.getSalary() >5000)
                .skip(2)
                .distinct()
                .forEach(System.out::println);
    }

  


}

2-マップ

方法 説明
map(関数f) 関数をパラメーターとして受け取り、関数は各要素に適用さ
れ、新しい要素にマップされます。
mapToDouble(ToDoubleFunction f) 関数を引数として取り、その関数が各要素
に適用されて、新しいDoubleStreamが生成されます。
mapToInt(ToIntFunction f) 関数を引数として取り、その関数が各要素
に適用されて、新しいIntStreamが生成されます。
mapToLong(ToLongFunction f) mapToLong(ToLongFunction f)
flatMap(関数f) 関数をパラメーターとして受け取り、ストリーム内の各値を別の
ストリームに置き換え、すべてのストリームを1つのストリームに連結します

例:

 /*
    *
    * 映射
    * map-接收Lambda,将元素转换成其它形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    * flatMap——接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
    *
    *
    * */
    @Test
    public void  test5(){
        List<String> list=Arrays.asList("aaaa","bbbb","ccc","dddd","eeee");
        list.stream()
               .map((str) ->str.toUpperCase())
                .forEach(System.out::println);

        System.out.println("---------------------");
        employees.stream()
                .map(Employee::getName)
               // .map((m)->m.getName()+"55")
                .forEach(System.out::println);

        System.out.println("---------------------");
        Stream<Stream<Character>> stream=list.stream()
                .map(TestStreamAPI2::filterCharacter);
        stream.forEach((sm)->{
          sm.forEach(System.out::println);
        });

        System.out.println("---------------------");
       Stream<Character> sm= list.stream()
                .flatMap(TestStreamAPI2::filterCharacter);
        sm.forEach(System.out::println);
    }



    public static Stream<Character> filterCharacter(String str){
        List<Character> list=new ArrayList<>();
        for(Character ch:str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }

3-並べ替え

方法 説明
sort()  自然な順序で並べ替えられた新しいストリームを生成します
ソート済み(コンパレータcom)  コンパレータ順にソートされた新しいストリームを生成します

 例

 /*
    *
    * 排序
    * sorted()-自然排序
    * sorted((Comparator com)-定制
    *
    *
    * */

    @Test
    public  void test7(){
        List<String> list=Arrays.asList("bbbb","aaaa","dddd","ccc","eeee");

        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("---------------------");

        employees.stream()
                .sorted((e1,e2)->{
                    if(String.valueOf(e1.getAge()).equals(String.valueOf(e2.getAge()))){

                        return e1.getName().compareTo(e2.getName());
                    }else {

                        return String.valueOf(e1.getAge()).compareTo(String.valueOf(e2.getAge()));
                    }
                }).forEach(System.out::println);

    }

ストリームの操作を終了します

 ターミナル操作は、ストリームのパイプラインから結果を生成します。結果は、ストリームではない任意の値になります。たとえば、List、Integer、さらにはvoidです。
ストリームが終了した後は、再度使用することはできません

1-一致して検索 

方法 説明
allMatch(述語p) すべての要素が一致しているかどうかを確認します
anyMatch(述語p)  少なくとも1つの要素が一致しているかどうかを確認します
noneMatch(述語p)  すべての要素が一致していないかどうかを確認します
findFirst()  最初の要素を返す
findAny() 現在のストリーム内の任意の要素を返します
カウント()  ストリーム内の要素の総数を返します
max(コンパレータc) ストリームの最大値を返します
min(コンパレータc) ストリーム内の最小値を返します
forEach(コンシューマーc) 内部反復(コレクションインターフェイスを使用するには、ユーザーが
外部反復と呼ばれる反復を実行する必要があります。対照的に、Stream APIは内部反復を使用します
-反復を実行します)

package com.chen.stream;


import com.chen.Employee;
import com.sun.org.apache.xerces.internal.util.Status;
import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/*
*
* 终止操作
*
*
* */
public class TestStreamApI3 {


    List<Employee> employees = Arrays.asList(
            new Employee(1,"张三1", 48,9999, Employee.Status.FREE),
            new Employee(2,"张三2", 38, 9999.99,Employee.Status.BUSY),
            new Employee(3,"张三3", 58, 1999.99,Employee.Status.VOCATION),
            new Employee(4,"张三4", 58, 5999.99,Employee.Status.FREE),
            new Employee(5,"张三5", 28, 5999.99,Employee.Status.BUSY),
            new Employee(6,"张三6", 28, 5999.99,Employee.Status.FREE),
            new Employee(7,"张三7", 58, 5999.99,Employee.Status.BUSY),
            new Employee(8,"张三8", 28, 5999.99,Employee.Status.FREE),
            new Employee(9,"张三9", 38, 5999.99,Employee.Status.BUSY)

    );


    /*
    * 查找与匹配
    * allMatch--检查是否匹配所有元素
    * anyMatch--检查是否至少匹配一个元素
    * noneMatch--检查是否没有匹配所有元素
    * findFirst--返回第一个元素
    * findAny--返回当前流中的任意元素
    * count--返回流中元素的总个数
    * max--返回流中最大值
    * min--返回流中最小值
    *
    *
    *
    *
    * */

    @Test
    public  void test11()
    {
       Optional<Employee> employee= employees.stream().findFirst();

       System.out.println( employee.get());

    }
    @Test
    public  void test1()
    {

       boolean b= employees.stream()
                .allMatch((e)-> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b);

       boolean b2= employees.stream()
                .anyMatch((e)-> e.getStatus().equals(Employee.Status.BUSY));
       System.out.println(b2);

       boolean b3= employees.stream()
               .noneMatch((e)-> e.getStatus().equals(Employee.Status.BUSY));
       System.out.println(b3);

       Optional<Employee> op=employees.stream()
               .sorted((e1,e2)-> -Double.compare(e1.getSalary(),e2.getSalary()))
               .findFirst();

       System.out.println(op.get());

       Optional<Employee> op2=employees.stream()
               .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
               .findAny();
       System.out.println(op2.get());





    }

    @Test
    public void test2(){
        Long count=employees.stream()
                .count();
        System.out.println(count);

        Optional<Employee> op1=employees.stream()
                .max((e1,e2) -> -Double.compare(e1.getSalary(),e2.getSalary()));
        System.out.println(op1.get());

        Optional<Double> op2=employees.stream()
                .map(Employee::getSalary)
                .min(Double::compare);
        System.out.println(op2.get());


    }

   
 

  

}

2-削減

方法 説明
reduce(T iden、BinaryOperator b) ストリーム内の要素を繰り返し組み合わせて、
値を取得できます。Tを返す
reduce(BinaryOperator b) ストリーム内の要素を繰り返し組み合わせて、
値を取得できます。オプション<T>を返す

ヒント:mapとreduceの接続は、しばしばmap-reduceパターンと呼ばれ、GoogleがWeb検索に使用することで有名です。

 /*
    * 归约
    * reduce(T identity,BinaryOperator) /reduce(BinaryOperator)--可以将流中元素反复结合起来,得到一个值
    *
    * */

    @Test
    public void test3(){
        List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        Integer sum=list.stream()
                .reduce(0,(x,y)-> x+y);
        System.out.println(sum);
        System.out.println("----------------");
        Optional<Double> op=employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(op.get());

    }

3-収集

方法 説明
収集(コレクターc) ストリームを別のフォームに変換します。ストリーム内の要素を要約するためのメソッドであるコレクター
インターフェイスの実装を受け取ります

  1. Collectorインターフェースのメソッドの実装は、ストリームで収集操作(List、Set、Mapへの収集など)を実行する方法を決定します。
  2. さらに、Collectorsユーティリティクラスは、一般的なコレクターのインスタンスを簡単に作成するための多くの静的メソッドを提供します。
  3. 具体的な方法と例は次のとおりです。

 

 /*
    *
    * 收集
    * collect--将流转换为其它形式。接受一个Collector接口的实现,用于给stream中元素做汇总的方法
    *
    * */
    @Test
    public void test4(){
        List<String> list=employees.stream()
               .map(Employee::getName)
                .collect((Collectors.toList()));
        list.forEach(System.out::println);

        System.out.println("----------------");
        Set<String> set=employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        set.forEach(System.out::println);

        System.out.println("--------------");

        HashSet<String> hs=employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hs.forEach(System.out::println);
    }

    @Test
    public void test5(){
        Long count=employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);

        System.out.println("---------------");

        //平均值
        Double avg=employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);

        //总和
        DoubleSummaryStatistics sum= employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(sum);

        System.out.println("---------------");
        //最大值
       Optional<Employee> max= employees.stream()
                .collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));

        System.out.println(max.get());

        //最小值
        Optional<Double> min=employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }

    /*
    *
    * 分组
    *
    * */
  @Test
    public void test6(){
      Map<Employee.Status,List<Employee>> map=employees.stream()
              .collect(Collectors.groupingBy(Employee::getStatus));
      System.out.println(map);


  }

  /*
  * 多级分组
  *
  * */

    @Test
    public void test7(){
        Map<Employee.Status, Map<String, List<Employee>>> collect = employees.stream()
                .collect((Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (((Employee) e).getAge() <= 35) {
                        return "青年";
                    } else if (((Employee) e).getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                }))));
                System.out.println(collect);
    }

    //分区
    @Test
    public  void test8(){

        Map<Boolean,List<Employee>> map=employees.stream()
                .collect(Collectors.partitioningBy((e)-> e.getSalary()>8000));
        System.out.println(map);


    }

    @Test
    public void test9(){
        DoubleSummaryStatistics dss=employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));

        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());
    }

    @Test
    public void test10(){
        String str=employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",","===","===="));
        System.out.println(str);
    }

オプションクラス

オプション<T>クラス(java.util.Optional)は、この値の存在を表すタイプTの値を保持できるコンテナークラスです。または、nullを格納して、値が存在しないことを示します。元々はnullを使用して値が存在しないことを示していましたが、現在はOptionalでこの概念をより適切に表現できます。ヌルポインタ例外を回避できます

オプションクラスのJavadocは、次のように説明しています。これはnull許容のコンテナオブジェクトです。値が存在する場合、isPresent()メソッドはtrueを返し、get()メソッドを呼び出すとオブジェクトが返されます

 オプションクラスのオブジェクトを作成するメソッド

  1.  Optional.of(T t):オプションのインスタンスを作成します。tはnull以外である必要があります。
  2.  オプション.empty():空のオプションインスタンスを作成します
  3.  オプション.ofNullable(T t):tはnullにすることができます

オプションのコンテナにオブジェクトが含まれているかどうかを確認します。

  1. boolean isPresent():オブジェクトが含まれているかどうかを判別します
  2. void ifPresent(Consumer <?super T> Consumer):値がある場合、Consumerインターフェースの実装コードが実行され、その値がパラメーターとして渡されます。

 オプションコンテナのオブジェクトを取得します。

  1. T get():呼び出し元のオブジェクトに値が含まれている場合は値を返し、そうでない場合は例外をスローします
  2. T orElse(T other):値がある場合は値を返し、そうでない場合は指定された他のオブジェクトを返します。
  3. T orElseGet(Supplier <?extends T> other)::値がある場合は値を返し、そうでない場合は、Supplierインターフェイス実装によって提供されるオブジェクトを返します。
  4. T orElseThrow(Supplier <?extends X> exceptionSupplier)::値がある場合はそれを返し、そうでない場合は、Supplierインターフェイス実装によって提供される例外をスローします。

@Test
public void test1() {
Boy b = new Boy("张三");
Optional<Girl> opt = Optional.ofNullable(b.getGrilFriend());
// 如果女朋友存在就打印女朋友的信息
opt.ifPresent(System.out::println);
}
@Test
public void test2() {
Boy b = new Boy("张三");
Optional<Girl> opt = Optional.ofNullable(b.getGrilFriend());
// 如果有女朋友就返回他的女朋友,否则只能欣赏“嫦娥”了
Girl girl = opt.orElse(new Girl("嫦娥"));
System.out.println("他的女朋友是:" + girl.getName());
}

@Test
public void test3(){
Optional<Employee> opt = Optional.of(new Employee("张三", 8888));
//判断opt中员工对象是否满足条件,如果满足就保留,否则返回空
Optional<Employee> emp = opt.filter(e -> e.getSalary()>10000);
System.out.println(emp);
}
@Test
public void test4(){
Optional<Employee> opt = Optional.of(new Employee("张三", 8888));
//如果opt中员工对象不为空,就涨薪10%
Optional<Employee> emp = opt.map(e ->
{e.setSalary(e.getSalary()%1.1);return e;});
System.out.println(emp);
}

おすすめ

転載: blog.csdn.net/qq_44716544/article/details/119065459