lamda表達式與Stream 流操作,reduce,flatMap,groupingBy等


/**
 * 符合lambda表達式的接口也叫函數式接口:
 * 除了默認方法和Object類的方法外,只有一個抽象方法的接口才能符合lambda表達式的要求
 * 可以使用@FunctionalInterface來校驗,如果沒報錯就是符合要求的
 *
 *
 */
@FunctionalInterface
public interface Animal {

    default String getName(){
        return "animal";
    }

    void eat();

}
//無參有返回
public interface Person {
    String getName();
}
//有參無返回
public interface Sckool {

    void learn(String name);
}
//有參有返回
public interface Student {
    String conCat(String str,String str2);
}
package lambda;

public class testLambda {
    public static void main(String[] args) {
        //要調用一個接口的方法,要么定義一個類來實現該接口,要么使用匿名內部類:
        //下面使用匿名內部類:

        eat(new Animal() {
            @Override
            public void eat() {
                System.out.println("動物吃東西");
            }
        });
        /**
         * 如果匿名內部類只有一個方法,可以使用lambda表達式替換:
         *  總共分下面4種情況:
         *          無參無返回格式:
         *              單條語句時()->xxx ;多條語句時()->{xx;aa;}
         *          無參有返回:
         *              單條語句時()->xxx;多條語句時()->{xx; return aa;}
         *          有參無返回:
         *              單條語句單個參數時:a->xxx;多條語句單個參數時a->{xx;cc;}
         *              單條語句多個參數時:(a,b)->xxx;多條語句多個參數時(a,b)->{xx;cc;}
         *
         *          有參有返回:
         *              單條語句單個參數時:a->xxx;多條語句單個參數時a->{xx;return cc;}
         *              單條語句多個參數時:(a,b)->xxx;多條語句多個參數時(a,b)->{xx; return cc;}
         */

        //-------- 無參無返回格式:
        //單條語句時()->xxx
        eat(()-> System.out.println("aaa"));

        //多條語句時()->{xx;aa;}
        eat(()->{
            System.out.println("dd");
            System.out.println("cc");
        });

        //---------無參數有返回格式:
        // 單條語句時()->xxx;
        String name=getName(()->"kk");

        //多條語句時()->{xx; return aa;}
        getName(()->{
            System.out.println("dd");
            return "cc";
        });

        //--------有參數無返回時

        //單條語句單個參數時
        learn(a-> System.out.println(a));

        //多條語句單個參數時a->{xx;cc;}
        learn(a->{
            System.out.println("lll");
            System.out.println("cc");
        });

        //單條語句多個參數時
        // learn((a,b)-> System.out.println(a+b));

        //多條語句多個參數時(a,b)->{xx;cc;}
        /**
         *
         *  learn((a,b)-> {
            System.out.println("lll");
            System.out.println("cc");
            });

         *
         */

        //---------有參數有返回

        //單條語句單個參數時:a->xxx;
        // learn(a-> "dd");

        //多條語句單個參數時a->{xx;return cc;}
        /**
         *   learn(a->{
                System.out.println("lll");
                 return "ss";
                });
         *
         *
         */

        //單條語句多個參數時:(a,b)->xxx
        String subject=concat((a,b)->a+b);

        //多條語句多個參數時(a,b)->{xx; return cc;}
        String subject2=concat((a,b)->{
            System.out.println("ddd");
            return a+b;
        });

        /**
         *
         * 我們使用lambda表達式時候,都是要實現一個方法,如果你要實現的方法剛好其他類有,那么就可以引用其他類的方法過來當做該匿名內部類的實現
         * 所以方法的引用分為:
         * 靜態方法的引用,如System.out:println
         * 非靜態方法的引用:如 new Dog()::eat;
         * 參數類型方法的引用,例如一個要實現的方法參數是String a,String b ,期望的結果是a+b,那么可以引用String::concat方法
         *
         *
         */

        learn(System.out::print); //剛好learn的內部類要實現的方法跟System.out的方法長得一樣,所以可以引用該方法當做自己的實現方法
        eat(new testLambda()::haveMeal);//非靜態方法的引用
        String str=concat(String::concat);//參數
        System.out.println(str);



    }

    public static void eat(Animal animal){
        animal.eat();
    }
    public static String getName(Person person){
        return person.getName();
    }
    public static void learn(Sckool sckool){
        sckool.learn("java");
    }
    public static String concat(Student student){
        return student.conCat("java","php");
    }

    public void haveMeal(){
        System.out.println("吃飯");
    }
}

 //stream 流:

package lambda;

import java.math.BigDecimal;

public class Cat {
    private String name;
    private BigDecimal price;

    public Cat(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}
package lambda;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class testLambda {
    public static void main(String[] args) {
        List<Cat> list=new ArrayList<>();
        list.add(new Cat("k",new BigDecimal("200")));
        list.add(new Cat("g",new BigDecimal("100")));
        list.add(new Cat("k",new BigDecimal("300")));
        list.add(new Cat("l",new BigDecimal("400")));
        list.add(new Cat("b",new BigDecimal("500")));
        list.add(new Cat("b",new BigDecimal("501")));
        /**
         * Stream流:跟IO的流是不一樣的,比較適當的比喻可以當做一個管道,數據從管道一端流經另一端,中間會經過多個操作,如過濾,排序
         *
         * 流程: 源 ------過濾----排序---終止-結果
         *
         * 所有操作分為三類
         * 1.創建流
         * 2.中間操作(惰性操作) : 凡是返回值類型是Stream的都是中間操作,如果只有中間操作,沒有終止操作,流是不會執行的
         * 3.終值操作
         *
         *
         *
         *  創建:
         *  Collection.stream();
         *  Arrays.asList("a","b").stream();
         *  Stream.of("a","b");
         *
         */

        /**
         * 流的特點:
         *   1.不能重復使用,每經過一個中間操作都返回新的流,之前的流就關閉了
         *   2.最多只能有一個終值操作,並且終值操作都是在最后
         *   3.執行順序:
         *      假如一個流經過 filter--sorted操作,順序是一個元素先經過filter--sorted 然后下一個元素經過filter--sorted,並不是所有元素先經過filter,然后經過sorted
         *
         *
         */
        Stream<Cat> stream = list.stream();
        //過濾操作是中間操作,如果沒有終值操作就不會執行
        Stream<Cat> stream2 = stream.filter(a -> {
            System.out.println("中間操作是惰性的,這句話不會輸出");
            return a.getName().equals("b");
        });
        //下面的操作會報錯:java.lang.IllegalStateException: stream has already been operated upon or closed
        //因為stream在上一步執行完filter就關閉了
        /*stream.filter(a-> {
            System.out.println("流不能重復使用");
            return a.getName().equals("b");
        }).toArray();*/

        Object[] bs = stream2.filter(a -> {
            System.out.println("有終值操作toArray,所以該方法會被執行");
            return a.getName().equals("b");
        }).toArray();

        //測試流是一個一個執行元素還是全部一起執行

        list.stream().filter(a->{
            System.out.println("過濾操作");
            return !a.getName().equals("oo");
        }).forEach(a-> System.out.println("遍歷操作"));  //輸出結果: 過濾操作 遍歷操作 過濾操作 遍歷操作 .....

        //常用的Strem API

        //過濾filter:上面的例子
        System.out.println(Arrays.toString(bs));

        //peek 和 forEach操作,peek不是終值操作,執行后還能繼續執行其他中間操作,forEach是終值操作

        list.stream().peek(System.out::println); //不會打印數據,因為中間操作是懶惰的
        list.stream().peek(System.out::println).toArray();
        list.stream().forEach(System.out::println);//終值操作,直接會輸出結果

        //map 將元素按照一定規則映射成另外一個元素
        List<String> nameList = list.stream().map(a -> a.getName()).collect(Collectors.toList());
        System.out.println(nameList);

        //distinct 去重
        List<String> distionctNameList = list.stream().map(a -> a.getName()).distinct().collect(Collectors.toList());
        System.out.println(distionctNameList);

        //sorted 排序
        List<Cat> sortList = list.stream().sorted((a, b) -> b.getPrice().compareTo(a.getPrice())).collect(Collectors.toList());
        System.out.println(sortList);
        //limit 操作
        List<Cat> limitList = list.stream().limit(2).collect(Collectors.toList());
        System.out.println(limitList);

        //mapToInt和reuduce用戶sum()操作時,調用int reduce(int identity, IntBinaryOperator op);所有元素op操作后加上identity的值就得到sum()的值了

        int reduce = list.stream().mapToInt(a -> a.getPrice().intValue()).reduce(0, (a, b) -> a + b); //2001
        int reduce2 = list.stream().mapToInt(a -> a.getPrice().intValue()).reduce(-1, (a, b) -> a + b);//2000
        int reduce3 = list.stream().mapToInt(a -> a.getPrice().intValue()).reduce(20, (a, b) -> a + b);//2021
        System.out.println(reduce);
        System.out.println(reduce2);
        System.out.println(reduce3);
     //BigDecimal payAmount = billMastList.stream().map(a -> a.getAmtBillPayment()).reduce(BigDecimal.ZERO, BigDecimal::add); 金額處理
//skip操作 跳過多少個元素,從1開始算 List<Cat> skipList = list.stream().skip(1).collect(Collectors.toList()); System.out.println(skipList); //價格最貴的 max(Comparator<? super T> comparator) Cat cat = list.stream().max((a, b) -> a.getPrice().compareTo(b.getPrice())).get(); System.out.println(cat); // boolean anyMatch(Predicate<? super T> predicate),判斷是否有比600價格貴的 boolean b = list.stream().allMatch(a -> a.getPrice().compareTo(new BigDecimal(600)) > 0); boolean b2 = list.stream().anyMatch(a -> a.getPrice().compareTo(new BigDecimal(500)) > 0); System.out.println(b); System.out.println(b2); //findAny() 獲取任意一個 Cat cat1 = list.stream().findAny().get(); System.out.println(cat1); //findFirst() 獲取第一個 Cat cat2 = list.stream().findFirst().get(); System.out.println(cat2); //flatMap:比較像降維打擊,如三維空間變成二維空間,具體的意思是每個元素經過處理,生成新的流.例如這里每個cat獲取它的名字組成一個新的集合 //再舉個例子,訂單跟商品,一個訂單集合經過flatMap,獲取每個訂單的商品集合組成一個新的流 List<String> flatMapList = list.stream().flatMap(a -> Stream.of(a.getName())).collect(Collectors.toList()); System.out.println(flatMapList);
    
       //list轉map 第一個參數是key值,第二個參數value值,第三個參數是key重復時,value如何進行合並
Map<String, BigDecimal> map = list.stream().collect(Collectors.toMap(a -> a.getName(), a -> a.getPrice(),(c, d)->c.add(d)));
System.out.println(map);





//分組功能
List<PerSon> list=new ArrayList<>();
list.add(new PerSon("yang",12));
list.add(new PerSon("yang",20));
list.add(new PerSon("ming",12));
list.add(new PerSon("ming",362));
list.add(new PerSon("tt",12));
list.add(new PerSon("kk",12));
Map<String, List<PerSon>> collect = list.stream().collect(Collectors.groupingBy(PerSon::getName)); //會分成四組,根據名字來分組

//注意 list轉map如果value值為null會報,如果key重復,不處理也會報錯,處理最好如下所示
custmerNameMap = customerInfoBatchList.stream().filter(a->StringUtils.isNotBlank(a.getCustomerName())) //過濾空值

.collect(Collectors.toMap(XfaceCustomerInfoListForBatchResponseSubDTO::getCustomerId, XfaceCustomerInfoListForBatchResponseSubDTO::getCustomerName,(k1,k2)->k1)); //
(k1,k2)->k1)代表key重復時,取第一個



//總結:所有API都不用記!!要用任何一個方法,點開Stream類可以查看到,或者idea工具提示可以找到任何一個方法,每個方法的參數都是一個接口,找到該接口看看其要實現的方法,然后使用lambda表達式就可以了  } }

 idea安裝插件可以對stream流進行debug:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM