java8 lambda stream學習

1. 簡介

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yR3VRVlA-1593843611869)(lambda.assets/image-20200704140545686.png)]

接口、匿名內部類可以採用lambda實現 格式 參數列表括號括起來 -> 功能體 stream則讓Java能夠像sql一樣操作集合等數據

lambda需要函數式接口的支持 函數式接口: 接口中只有一個抽象方法的接口 @FunctionalInterface 修飾一下

Lambda 就相當於接口、匿名內部類的簡便寫法

    @Test 
    public void test1() {
        Comparator<Integer> com0 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
        Comparator<Integer> com2 = Comparator.comparingInt(x -> x);
        Comparator<Integer> com3 = Integer::compare;
      
        List<Employee> employees = filterEmployee(employeeList, e -> e.getSalary() >= 5000);
        employees.forEach(System.out::println);
      
     		employeeList
                .stream()
                .filter(x -> x.getSalary() > 5000)
                .limit(2)
                .forEach(System.out::println);

        employeeList
                .stream()
                .map(Employee::getName)
                .forEach(System.out::println);

      //Collections在lambda中很常用
       @Test
    public void test8() {
        Collections.sort(employeeList, (e1, e2) -> {
            if (e1.getAge() == e2.getAge()) {
                return e1.getName().compareTo(e2.getName());
            } else {
                return Integer.compare(e1.getAge(), e2.getAge());
            }
        });
    }
      
    }

2. 語法格式

  • 格式一: 無參數、無返回值

     Runnable r2=() -> System.out.println("runnable test");
    
  • 格式二: 有一個參數、無返回值(一個參數小括號可以省略)

    Consumer<String> con = (x) -> System.out.println(x); 
    Consumer<String> con = x -> System.out.println(x); 
    Consumer<String> con = System.out::println; //idea 智能生成
    
  • 格式三: 只有一條語句、大括號和return都可以省略不寫

     Comparator<Integer> com =(x,y)->{
        return Integer.compare(x,y);
            };
    Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
    
  • 格式四: 參數類型可以省略不寫,Java根據上下文可以推斷出來 類型推斷

3. 四大內置接口

lambda需要函數式接口的支持,有時需要我們自己去創建函數式接口去支持,但Java8已經內置四大函數式接口

1. 消費型接口Consumer<T>

// 消費型接口 無返回值
Consumer<T>:
		void accept(T t); 


  public void consumerInterface(double money, Consumer<Double> con) {
        //具體實現在lambda表達式裏面體現
        con.accept(money);
    }
    
    public void test9(){
        consumerInterface(1000,(m)-> System.out.println("consumer"+m));
    }

2. 供給型接口Supplier<T>

Supplier<T>:
	T get()
    
  //產生元素
    public List<Integer> getNumList(int num, Supplier<Integer> sup) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
              //具體實現在lambda表達式裏面體現
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }

    @Test
    public void test10() {
        //沒有輸入參數,所以爲空 () ->
        List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 1000));
        for (Integer integer : numList) {
            System.out.println(integer);
        }
    }

3. 函數型接口Function<T,R>

Function<T,R>
  	apply(T)

public void strHandeler(String str, Function<String, String> fun) {
      //具體實現在lambda表達式裏面體現
        fun.apply(str);
    }

    @Test
    public void test11() {
//        strHandeler(" a b c d",(str) -> str.trim());
        strHandeler("a b c d", String::trim);

//        strHandeler("a b c d ",str -> str.toUpperCase());
        strHandeler("a b c d", String::toUpperCase);
    }

4. 斷言型接口Predicate<T>

Predicate<T>
  	boolean test(T t)
  
  
   public List<String> filterStr(List<String> list, Predicate<String> predicate){
        ArrayList<String> arrayList = new ArrayList<>();

        for (String s : list) {
            //具體實現在lambda表達式裏面體現
            if(predicate.test(s)){
                arrayList.add(s);
            }
        }
        return arrayList;
    }

    @Test
    public void test12(){
        List<String> asList = Arrays.asList("hello", "java", "lambda");
        List<String> strings = filterStr(asList, s -> s.length() > 3);
    }

4. 方法引用

若lambda體中的內容已經有方法實現了,那麼就可以使用方法引用,方法引用就像下面的,算是lambda的特殊表達方式 xxx::xx

//       strHandeler(" a b c d",(str) -> str.trim());
//      String類已經做好了trim方法,就直接調用String::trim即可
        strHandeler("a b c d", String::trim);

//再比如 直接調用 System.out的方法println
Consumer<String> con = x -> System.out.println(x)
Consumer<String> con = System.out::println 
  
Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Comparator.comparingInt(x -> x);
Comparator<Integer> com3 = Integer::compare;

使用要求: 已實現方法的參數列表、返回值類型必須和使用lambda表達式的參數列表、返回值類型一致纔可以

比如:

Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com3 = Integer::compare;

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

Integer.compare 方法接收的參數列表爲兩個、返回值爲int與使用lambda表達式一致

主要有以下三種類型

  • 對象::實例方法名 empList::getName //後面的()都可以省略 getName()
  • 類::靜態方法名
  • 類::實例方法名 // 用在(x,y) -> x.equal(y) 等同於 String::equals 接收兩個參數 第一個參數爲方法調用者,第二個參數爲方法參數

5. 構造器引用

格式: ClassName::new 會根據左側類中方法的參數去自動匹配右側方法的哪個構造方法

Supplier<Employee> sup = () -> new Employee();

// 會根據左側類中方法的參數去自動匹配右側方法的哪個構造方法
// 無參構造器、一參構造器、多參構造器 
Supplier<Employee> sup2 = Employee::new; 

數組引用: Type[]::new

Function<Integer,String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);

Function<Integer,String[]> fun2 = String[]::new;
String[] str2 = fun2.apply(20);

6. Stream

  1. 簡介: Stream 能夠使數據源(集合、數組等)轉換爲流然後執行一系列的流水式的中間操作(filter 過濾) 篩選 切片等產生一個新的流,而原來的數據源不會發生任何改變, 類似於sql操作數據 集合是數據,流是計算

  2. 注意點: Stream不會存儲元素,不會改變源對象,返回持有結果的心Stream,操作延時,需要等到結果時才執行

  3. 步驟 :創建Stream、中間操作、終止操作

    public class aaa {
    
     List<Employee> employeeList = Arrays.asList(
                new Employee("張三", 18, 9999.99, Employee.Status.FREE),
                new Employee("李四", 25, 789.99, Employee.Status.BUSY),
                new Employee("王武", 12, 2359.99, Employee.Status.BUSY),
                new Employee("趙六", 78, 4569.99, Employee.Status.BUSY),
                new Employee("王二", 34, 956789.99, Employee.Status.VOCATION),
                new Employee("王八", 88, 329.99, Employee.Status.VOCATION),
                new Employee("牛二", 23, 953699.99, Employee.Status.BUSY),
                new Employee("狗蛋", 67, 95654.99, Employee.Status.FREE)
        );
    
        //創建Stream
        @Test
        public void test1() {
            // 1 可以通過Collection系列集合提供的stream() 串行流  或 parallelStream() 並行流
            List<String> list = new ArrayList<>();
            Stream<String> stream1 = list.stream();
    
            // 2 通過Arrays中的靜態方法stream() 獲得數組流
            Employee[] employees = new Employee[10];
            Stream<Employee> stream2 = Arrays.stream(employees);
    
            // 3 通過stream()類中的靜態方法 of()
            Stream<String> stream3 = Stream.of("aa", "bb", "cc");
    
            // 4 創建無限流
            // 迭代
            Stream<Integer> stream4 = Stream.iterate(0, x -> x * 2);
    
            //生成
            Stream<Double> generate = Stream.generate(() -> Math.random());
        }
    
    
        //中間操作
        //不會執行任何的操作,惰性求值
        @Test
        public void test2() {
    
            //過濾 filter
            employeeList.stream()
                    .filter(x -> x.getAge() > 35)
                    .forEach(System.out::println);
    
            employeeList.stream()
                    .filter((e) -> {
                        System.out.println("短路");
                        return e.getAge() > 35;
                    }).forEach(System.out::println);
    
    
            // 截取 limit
            employeeList.stream()
                    .limit(2)
                    .forEach(System.out::println);
    
    
            // 跳過 skip(n) 扔掉前n個,返回後面的元素,如果不滿n 則返回空流 與 limit互補
            employeeList.stream()
                    .skip(2)
                    .forEach(System.out::println);
    
    
            // 去重 distinct 通過hashCode 和 equal 去重 需要有hashCode equal方法
            employeeList.stream()
                    .distinct()
                    .forEach(System.out::println);
    
    
            //map 一般 直接 類::方法 class::method
            // 映射 map 接收一個lambda將元素轉換成其他形式或提取信息
            // 接收一個函數作爲參數,該函數會應用到每個元素上,並將其映射成新的元素
            // scala很簡單經常用
            List<String> asList = Arrays.asList("aa", "bb", "cc");
            asList.stream()
    //                .map(l -> l.toUpperCase())
                    .map(String::toUpperCase)
                    .forEach(System.out::println);
            employeeList.stream()
                    .map(Employee::getName)
                    .forEach(System.out::println);
    // flatMap 壓平
    
    
            //排序
            employeeList.stream()
    //                .sorted()
                    .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);
        }
    
    
        //終止操作
        @Test
        public void termianteed() {
    /**
     * 匹配
     * allMatch-檢查是否匹配所有元素 是true 否false
     * anyMatch 檢查是否有一個匹配
     * noneMatch 檢查是否沒有匹配的 false說明至少有一個匹配 true沒有一個匹配的 雙重否定->肯定
     *
     * 查找
     * findFirst 返回第一個元素
     * findAny  返回當前流中的任意一個
     */
    
            boolean busy = employeeList.stream()
                    .allMatch(e -> e.getStatus().equals("BUSY"));
    
            boolean busy1 = employeeList.stream()
                    .anyMatch(e -> e.getStatus().equals("BUSY"));
    
            boolean busy2 = employeeList.stream()
                    .noneMatch(e -> e.getStatus().equals("BUSY"));
    
    
            Optional<Employee> first = employeeList.stream()
                    .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                    .findFirst();
    
            // option 看來 java的lambda與scala很像啊
    
    //        employeeList.stream()
            employeeList.parallelStream()
                    .filter(e -> e.getStatus().equals("FREE"))
                    .findAny();
    
    
            // count max min
            employeeList.stream()
                    .count();
    
            employeeList.stream()
                    .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
    
            //最少的工資
            employeeList.stream()
                    .map(Employee::getSalary)
                    .min(Double::compare);
    
    
            //歸約 reduce 從scala的角度來看,這就很easy了
            Arrays.asList(1, 2, 3, 4, 5).stream()
                    //初始值 操作方法
                    .reduce(0, Integer::sum);
    
            employeeList.stream()
                    .map(Employee::getSalary)
                    .reduce(Double::sum);
    
    
            //收集 collect收集流中的元素
            employeeList.stream()
                    .map(Employee::getName)
    //                .collect(Collectors.toList());
                    .collect(Collectors.toCollection(HashSet::new));
    
            //分組
            employeeList.stream()
                     .collect(Collectors.groupingBy(Employee::getStatus));
    
            employeeList.stream()
                    .map(e->1)
                    .reduce(Integer::sum);
    
        }
    }
    
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章