天天看點

Java8新特性——Stream API

1、stream API——相識

       Stream是元素的集合,這點讓Stream看起來有些類似Iterator;可以支援順序和并行的對原Stream進行彙聚的操作。

       大家可以把Stream當成一個進階版本的Iterator。原始版本的Iterator,使用者隻能一個一個的周遊元素并對其執行某些操作;高版本的Stream,使用者隻要給出需要對其包含的元素執行什麼操作,比如:“過濾掉長度大于10的字元串”、“擷取每個字元串的首字母”等,這些操作如何應用到每個元素上,就給Stream就好了!

2、Stream API——建立、中間操作、終止操作(終端操作)

        建立:一個資料源(如:集合、數組),擷取一個流。

//    建立Stream
    @Test
    public void fun1(){
//      1.可以通過Collection系列集合提供的stream()串行流或parallelStream()并行流

        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

//      2.通過Arrays中的靜态方法stream()獲得數組流
        Employee [] emps = new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(emps);

//      3.通過Stream類中的靜态方法of()
        Stream<String> stream3 = Stream.of("aa","bb","cc");

//      4.建立無限流
//         (1)疊代
        Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
        stream4.limit(10)
               .forEach(System.out::println);
//        (2)生成
        Stream.generate(() -> Math.random())
              .limit(5)
              .forEach(System.out::println);
    }
           

       中間操作:一個中間操作鍊,對資料源的資料進行處理。

                 (1)、篩選與切片

//    中間操作
    /*
     篩選和切片
        filter——接收Lambda,從流中排除某些元素。
        limit——截斷流,使其元素不超過給定數量。
        skip(n)——跳過元素,傳回一個扔掉了前n個元素的流,若流中元素不足n個時,則傳回一個空流,與limit互補
        distinct——篩選,通過流所生成元素的HashCode()和equals()去除重複元素
    */
List<Employee> employees = Arrays.asList(
        new Employee("張三",18,9999.99),
        new Employee("張三",18,9999.99),
        new Employee("張三",18,9999.99),
        new Employee("張三",18,9999.99),
        new Employee("張三",18,9999.99),
        new Employee("張三",18,9999.99),
        new Employee("李四",18,8888.88),
        new Employee("王五",100,1.11),
        new Employee("趙六",80,2.22),
        new Employee("田七",20,9898.98)
    );
    /*内部疊代:疊代操作由Stream API完成*/
    @Test
    public void fun2(){
//        中間操作:不會執行任何操作
        Stream<Employee> stream = employees.stream()
                .filter((e) -> {
                    System.out.println("Stream API的中間操作");
                    System.out.println("沒有終止操作的話,中間操作不執行。");
                    return e.getAge() > 35;
                });
//    終止操作:一次性執行全部内容,即惰性求值
        stream.forEach(System.out::println);
    }
    /*外部疊代*/
    @Test
    public void fun3(){
        Iterator<Employee> iterator = employees.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    @Test
    public void fun4(){
        employees.stream()
                  .filter((e) -> {
                      System.out.println("短路!"); //&& ||
                  return e.getSalary() >5000;
                  })
                  .limit(2)
                  .forEach(System.out::println);
    }
    @Test
    public void fun5(){
        employees.stream()
                  .filter((e) -> e.getSalary()>5000)
                  .skip(2)
                  .forEach(System.out::println);
    }

    @Test
    public void fun6(){
        employees.stream()
                .filter((e) -> e.getSalary()>5000)
                .distinct()
                .forEach(System.out::println);
    }
           
package Lambda.LambdaCase;

public class Employee {
    private String name;
    private Integer age;
    private Double salary;

    public Employee() {
    }

    public Employee(Integer age) {
        this.name = name;
    }

    public Employee(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Employee(String name, Integer age, Double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        if (!name.equals(employee.name)) return false;
        if (!age.equals(employee.age)) return false;
        return salary.equals(employee.salary);
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age.hashCode();
        result = 31 * result + salary.hashCode();
        return result;
    }

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

       (2).映射

/*
      映射
        map——接收lambda,将元素轉換成其他形式或提取資訊。
               接收一個函數作為參數,該函數會應用到每個元素上,并将其映射成一個新的元素。
        flagMap——接收一個函數作為參數,将流中的每個值都換成另一個流,然後把所有流連接配接成一個流。
    */
    @Test
    public void fun7(){
        List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
        list.stream()
            .map((str) -> str.toUpperCase())
            .forEach(System.out::println);
        System.out.println("------------我是分割線-------------");
        employees.stream()
                  .map(Employee::getName)
                  .forEach(System.out::println);

        System.out.println("------------我是分割線-------------");
        Stream<Stream<Character>> stream = list.stream()
                .map(GetUnlimitedFlow::filterCharacter);//{{a,a,a},{b,b,b}}
        stream.forEach((sm) ->{
            sm.forEach(System.out::println);
        });

        System.out.println("------------我是分割線-------------");
        Stream<Character> stream1 = list.stream()
                .flatMap(GetUnlimitedFlow::filterCharacter);//{a,a,a,b,b,b}
        stream1.forEach(System.out::println);

    }
    /*解析字元串,将字元串中的字元一個個列印出來*/
    public static Stream<Character> filterCharacter(String str){//add(Object obj)  addAll(Collection coll)
        ArrayList<Character> list = new ArrayList<>();
        for (Character ch:str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    @Test
    public void fun8(){
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        ArrayList list1 = new ArrayList();
        list1.add(11);
        list1.add(33);
//        list1.add(list);
//        System.out.println(list1);
        list1.addAll(list);
        System.out.println(list1);
    }
           

    (3).排序

/*
      排序
         sorted()——自然排序(Comparable)
         sorted(Comparator com)——定制排序(Comparater)
    */
    @Test
    public void fun9(){
        List<String> list = Arrays.asList("bbb", "ddd", "aaa", "eee", "ccc");
        list.stream()
            .sorted()
            .forEach(System.out::println);
        System.out.println("------------我是分割線-------------");
        employees.stream()
                  .sorted((e1,e2) -> {
                    if (e1.getAge().equals(e2.getAge())){
                        return e1.getName().compareTo(e2.getName());
                    }else {
                        return -e1.getAge().compareTo(e2.getAge());
                    }
                  }).forEach(System.out::println);
    }
           

       終止操作:一個終止操作,執行中間操作鍊,并産生結果。

     查找與比對

List<Employee> employees1 = Arrays.asList(
            new Employee("張三",18,9999.99, Employee.Status.BUSY),
            new Employee("李四",18,8888.88, Employee.Status.FREE),
            new Employee("王五",100,1.11, Employee.Status.VOCATION),
            new Employee("趙六",80,2.22, Employee.Status.FREE),
            new Employee("田七",20,9898.98, Employee.Status.BUSY)
    );
    /*
      查找與比對
         allMatch——檢查是否比對所有元素
         anyMatch——檢查是否至少比對一個元素
         noneMatch——檢查是否沒有比對所有元素
         findFirst——傳回第一個元素
         findAny——傳回目前流中的任意元素
         count——傳回流中元素的總個數
         max——傳回流中最大值
         min——傳回流中最小值
    */
    @Test
    public void fun10(){

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

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

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

        Optional<Employee> op = employees1.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println(op.get());

        Optional<Employee> any = employees1.stream()
                .filter((e) -> e.getStatus().equals(Employee.Status.BUSY))
                .findAny();
        System.out.println(any.get());
    }

    @Test
    public void fun11() {
        long count = employees1.stream()
                .count();
        System.out.println(count);

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

        Optional<Double> min = employees1.stream()
                .map(Employee::getSalary)
                .min(Double::compare);
        System.out.println(min.get());
    }
           
歸約      
/*
      歸約
        reduce(T identity,BinaryOperator)/reduce(BinaryOperator)
            ——可以将流中元素反複結合起來,得到一個值
    */
    @Test
    public void fun12(){
        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> reduce = employees1.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(reduce.get());
    }
           

    收集

/*
     收集:
        collect——将流轉換為其他形式,接收一個Collector接口的實作,
                   用于給Stream中元素做彙總的方法。
    */
    @Test
    public void fun13(){
        List<String> list = employees1.stream()
                                       .map(Employee::getName)
                                       .collect(Collectors.toList());
        list.forEach(System.out::println);

        System.out.println("------------我是分割線-------------");

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

        System.out.println("------------我是分割線-------------");

        HashSet<Double> hashSet = employees1.stream()
                .map(Employee::getSalary)
                .collect(Collectors.toCollection(HashSet::new));
        hashSet.forEach(System.out::println);
    }

    @Test
    public void fun14(){
//      總數
        Long count = employees1.stream()
                .collect(Collectors.counting());
        System.out.println(count);

        System.out.println("------------我是分割線-------------");
//      平均值
        Double avg = employees1.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);

        System.out.println("------------我是分割線-------------");
//        總和
        Double sum = employees1.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);

        System.out.println("------------我是分割線-------------");
//      最大值
        Optional<Employee> max = employees1.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());

        System.out.println("------------我是分割線-------------");
//       最小值
        Optional<Double> min = employees1.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }
           

   分組和多級分組

@Test
    public void fun15(){
//      分組
        Map<Employee.Status, List<Employee>> map = employees1.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
    }
//      多級分組
    @Test
    public void fun16(){
        Map<Employee.Status, Map<String, List<Employee>>> mapMap = employees1.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() < 5) {
                        return "青年";
                    } else if (e.getAge() < 10) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        System.out.println(mapMap);
    }
           

  分區

//    分區
    @Test
    public void fun17(){
        Map<Boolean, List<Employee>> partition = employees1.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
        System.out.println(partition);
    }
           

  彙總統計

//  彙總統計
    @Test
    public void fun18(){
        DoubleSummaryStatistics summary = employees1.stream()
                                                     .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(summary);
        System.out.println(summary.getAverage());
        System.out.println(summary.getCount());
        System.out.println(summary.getMax());
        System.out.println(summary.getMin());
        System.out.println(summary.getSum());
    }
           

  字元串拼接

//  字元串拼接
    @Test
    public void fun19(){
        String join = employees1.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",","===","==="));
        System.out.println(join);

    }
           
Java8新特性——Stream API
package Steam;

import Lambda.LambdaCase.Employee;
import org.junit.Test;

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

public class TestStreamAPI {
    /*
      1、給定一個數字清單,如何傳回一個由每個數的平方構成的清單呢?
         給定【1,2,3,4,5】,應該傳回【1,4,9,16,25】
    */
    @Test
    public void fun1(){
        Integer [] arr = new Integer[]{1,2,3,4,5};
        Arrays.stream(arr)
              .map((x) -> x*x)
              .forEach(System.out::println);
    }
    /*
      2、怎樣用map和reduce方法數一數流中有多少個Employee?
    */
    List<Employee> employees = Arrays.asList(
            new Employee("張三",18,9999.99, Employee.Status.BUSY),
            new Employee("李四",18,8888.88, Employee.Status.FREE),
            new Employee("王五",100,1.11, Employee.Status.VOCATION),
            new Employee("趙六",80,2.22, Employee.Status.FREE),
            new Employee("田七",20,9898.98, Employee.Status.BUSY)
    );
    @Test
    public void fun2(){
        Optional<Integer> sum = employees.stream()
                .map((e) -> 1)
                .reduce(Integer::sum);
        System.out.println(sum.get());
    }
}