JavaSEday13Lambda、函數式接口和Stream流

day13_面向對象(Stream流)
    一.Lambda表達式
        1.函數式編程的思想
            強調/注重三個方面:輸入量,計算過程,輸出量
            不注重格式/形式
        2.冗餘的Runnable代碼

public class RunnableDemo {
    public static void main(String[] args) {
        //1.創建一個線程,並啓動,使用實現類
//        new Thread(new MyRunnable()).start();
        //2.創建一個線程,並啓動,使用匿名內部類
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("線程執行了...");
            }
        }).start();
    }
}
//a.由於新建一個實現類麻煩,我們不得不採用匿名內部類
//b.由於Thread構造中指明瞭需要Runnable的實現類,我們不得不new一個Runnable
//c.由於接口中抽象方法爲run,那麼重寫葉必須是run
//d.而實際上我們真正想要的其實簡單,就是任務

        3.函數式編程Lambda的體驗
          

 new Thread(()->{
            System.out.println(
                Thread.currentThread().getName()+"..線程執行了..");
        }).start();

        4.Lambda標準格式介紹****************
            (參數列表) -> {方法體;return 返回值;}            Collections和Arrays裏的sort方法區別在於Arrays.sort()只能對引用類型數組進行排序
        5.Lambda的參數和返回值**************

public class ComparatorDemo {
    public static void main(String[] args) {
        //1.集合
        ArrayList<Integer> arr = new ArrayList<Integer>();
        arr.add(3);
        arr.add(23);
        arr.add(13);
        arr.add(43);
        arr.add(53);
        arr.add(23);
        //2.排序 降序
//        Collections.sort(arr, new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                //降序
//                return o2 - o1;
//            }
//        });
        //使用Lambda代替匿名內部類
        Collections.sort(arr,(Integer o1, Integer o2)->{return o2 - o1;});
        //3.打印
        System.out.println(arr);
    }
}

public class ComparatorDemo02 {
    public static void main(String[] args) {
        //自定義類型的數組
        Dog[] dogs = new Dog[4];
        //賦值
        dogs[0] = new Dog(22, "旺財");
        dogs[1] = new Dog(2222, "來福");
        dogs[2] = new Dog(222, "哮天犬");
        dogs[3] = new Dog(2, "楊戩");
        //排序,按照Dog的年齡降序
//        Arrays.sort(dogs, new Comparator<Dog>() {
//            @Override
//            public int compare(Dog o1, Dog o2) {
//                //按照狗的年齡降序
//                return o2.age-o1.age;
//            }
//        });
        //使用Lambda優代替匿名內部類
        Arrays.sort(dogs,(Dog o1, Dog o2)->{return o2.age-o1.age;});
        //打印
        for (Dog dog : dogs) {
            System.out.println(dog);
        }
    }
}

            表面上Lambda是匿名內部類的語法糖(格式簡化),但是彼此底層實現不同,匿名內部類面向對象,Lambda是面向虛擬機的,直接翻譯成虛擬機指令,執行效率更高
        6.Lambda的省略格式************
            a.參數的數據類型。可以無條件省略
            b.如果參數只有一個,那麼小括號也可以省略
            c.如果方法體和返回值語句可以寫成一句話,那麼{},return,以及;可以同時(都要省略,不然報錯)省略

//體驗一下函數式編程(Lambda)的優雅代碼
new Thread(()->{System.out.println(Thread.currentThread().getName());}).start();
//Lambda的省略格式
new Thread(()->System.out.println(Thread.currentThread().getName())).start();


//使用Lambda代替匿名內部類
Collections.sort(arr,(Integer o1, Integer o2)->{return o2 - o1;});
//Lambda的省略格式
Collections.sort(arr,(o1,o2)->o2 - o1);


//使用Lambda優代替匿名內部類
Arrays.sort(dogs, (Dog o1, Dog o2) -> { return o2.age - o1.age; });
//Lambda的省略格式
Arrays.sort(dogs, (o1, o2) -> o2.age - o1.age);

        7.強烈注意:Lambda的使用前提
            a.Lambda只能用於替代只有一個抽象方法的接口的匿名內部類
            b.Lambda的省略格式只有以上三種,其他方面均不能省略(因爲可推導纔可省略)
    二.函數式接口
        1.什麼叫函數式接口
            首先也是一個接口。可以支持函數式編程的接口,可以給Lambda使用的接口,就是隻有一個抽象方法的接口

//這就是函數式接口
public interface MyInterface {
    void show();
}

        2.函數式接口註解
            @FunctionalInterface(當之後接口不符合函數式接口規範就會報錯)(Runnable和Comparator均是函數式接口)
@FunctionalInterface
public interface MyInterface {
    void show();
}

        3.常用的函數式接口
            a.自定義函數式接口

/**
 * 廚師接口
 */
@FunctionalInterface
public interface Cook {
    void cookFood(String name);
}
public class CookDemo {
    public static void main(String[] args) {
        //調用方法
        //使用具體的實現類
        //method(new Cook的實現類對象());
        //使用匿名內部類
//        method(new Cook() {
//            @Override
//            public void cookFood(String name) {
//                System.out.println("清蒸"+name+"做好了...");
//            }
//        });
        //使用Lambda
        method((String name)->{System.out.println("清蒸"+name+"做好了...");});
        //省略
        method(name->System.out.println("清蒸"+name+"做好了..."));
    }

    //定義方法:請一個廚師做飯
    public static void method(Cook cc) {
        cc.cookFood("蝦");
    }
}


            b.Consumer<T>函數式接口,消費接口

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);//該方法接收一個數據,沒有返回值
}
public class ConsumerTestDemo {
    public static void main(String[] args) {
        //調用method
//        method(new 接口實現類對象());
        //使用匿名內部類
        method(new Consumer<String>() {
            @Override
            public void accept(String s) {
                //打印到控制檯
                System.out.println(s);
                //保存到數據庫
                //發送到網絡
            }
        });
        //使用Lambda
        method((String s) -> { System.out.println(s); });
        //省略
        method(s -> System.out.println(s));

    }

    //定義一個方法:接收一個消費者接口
    public static void method(Consumer<String> con) {
        //調用方法
        con.accept("java");
    }
}

            c.Predicate<T>函數式接口,判斷接口

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);//判斷一個數據是否符合要求
}
public class PredicateTestDemo {
    public static void main(String[] args) {
        //調用方法
//        method(new Predicate接口的實現類());
        //使用匿名內部類
        method(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //如果字符串長度大於5個,符合
                return s.length() > 5;
            }
        });
        //使用Lambda
        method((String s)->{return s.length() > 5;});
        //省略
        method(s->s.length() > 5);
    }
    //定義方法,接收一個判斷接口
    public static void method(Predicate<String> pp) {
        //調用
        boolean b = pp.test("Hello");
        System.out.println("該字符串符合要求嗎?" + b);
    }
}

    三.Stream流******************
        1.引入:傳統的集合操作

public class ForeachDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("張無忌");
        list.add("周芷若");
        list.add("趙敏");
        list.add("張強");
        list.add("張三丰");
        //1. 首先篩選所有姓張的人;
        ArrayList<String> zhangs = new ArrayList<String>();
        for (String name : list) {
            //判斷
            if (name.startsWith("張")) {
                zhangs.add(name);
            }
        }

        //2. 然後篩選名字有三個字的人;
        ArrayList<String> threes = new ArrayList<String>();
        for (String zhang : zhangs) {
            if (zhang.length() == 3) {
                threes.add(zhang);
            }
        }

        //3. 最後進行對結果進行打印輸出
        for (String name : threes) {
            System.out.println(name);
        }

    }
}

        2.循環遍歷的弊端分析
            a.每次都要循環遍歷,很麻煩
            b.循環是格式固定,注重形式
        3.Stream的優雅寫法****************

//體驗Stream的優雅代碼
list.stream().filter(s->s.startsWith("張")).filter(s->s.length()==3).forEach(s-> System.out.println(s));

        4.流式思想的概述
             
        5.兩種獲取流的方式***************
            a.集合獲取流(單列集合)
                Collection集合調用stream()方法直接獲取流
            b.數組獲取流
                調用Stream的靜態方法of(可變參數/數組)獲取流
                注意:如果是數組,該數組必須是引用類型,如果需要基本類型,寫包裝類(不然報錯)

public class StreamDemo {
    public static void main(String[] args) {
//        a.集合獲取流
        ArrayList<String> arr1 = new ArrayList<String>();
        Stream<String> orignal1 = arr1.stream();

        HashSet<Integer> set = new HashSet<Integer>();
        Stream<Integer> orignal2 = set.stream();
//        b.數組獲取流
//        Integer[] nums = {1,2,3,4,5};
//        Stream<Integer> orignal3 = Stream.of(nums);
        Stream<Integer> orignal3 = Stream.of(1, 2, 3, 4, 5);
    }
}

        6.Stream流中的常用方法
            a.過濾:filter(new Predicate<T>(){});
            b.統計個數:count();
            c.取前幾個:limit(long count);
            d.跳過前幾個:skip(long count);
            e.逐個處理(消費數據):foreach(new Consumer<T>(){});
            f.靜態方法合併Stream

public class StreamDemo02 {
    public static void main(String[] args) {
        //1.獲取流
        Stream<String> orignal = Stream.of("jack", "rose", "tom", "marry", "jerry", "hanmeimei");
        //2.過濾
//        Stream<String> stream01 = orignal.filter(new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                //要字符串長度大於4
//                return s.length() > 4;
//            }
//        });
        Stream<String> stream01 = orignal.filter(s-> s.length() > 4);
        //3.計數方法
        long count = stream01.count();
        System.out.println(count);
        //4.取前幾個
        Stream<String> stream02 = stream01.limit(2L);
        System.out.println(stream02.count());
        //5.跳過前幾個
        Stream<String> stream03 = stream01.skip(2);
        System.out.println(stream03.count());
        //6.逐一消費
//        stream01.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });
        stream01.forEach(s->System.out.println(s));

        //創建兩個流
        Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
        Stream<Integer> stream2 = Stream.of(1,2,3,6,7,8,9);
        Stream<Integer> stream3 = Stream.of(10,20,30);
        //合併
        Stream<Integer> stream = Stream.concat(stream1, stream2);
        Stream<Integer> stream4 = Stream.concat(stream, stream3);
        //逐一消費
        stream4.forEach(s-> System.out.println(s));
    }
}


        7.練習:集合元素的處理(傳統方式)
        8.練習:集合元素的處理(Stream方式)****************

public class StreamDemo03 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪麗熱巴");
        one.add("宋遠橋");
        one.add("蘇星河");
        one.add("老子");
        one.add("莊子");
        one.add("孫子");
        one.add("洪七公");

        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("張無忌");
        two.add("張三丰");
        two.add("趙麗穎");
        two.add("張二狗");
        two.add("張天愛");
        two.add("張三");

//        1. 第一個隊伍只要名字爲3個字的成員姓名;
//        2. 第一個隊伍篩選之後只要前3個人;
        Stream<String> stream01 = one.stream().filter(s -> s.length() == 3).limit(3L);
//        3. 第二個隊伍只要姓張的成員姓名;
//        4. 第二個隊伍篩選之後不要前2個人;
        Stream<String> stream02 = two.stream().filter(s -> s.startsWith("張")).skip(2L);
//        5. 將兩個隊伍合併爲一個隊伍;
        Stream<String> totalStream = Stream.concat(stream01, stream02);
//        6. 打印整個隊伍的姓名信息。
        totalStream.forEach(s -> System.out.println(s));
    }
}

        9.總結:函數拼接和終結方法
            函數拼接方法:調用方法之後,返回還是流對象
                filter,limit,skip,concat
                所有的函數拼接方法,都支持鏈式編程
            終結方法:調用方法之後,沒有返回值,或者返回不是流對象
                count,foreach
                所有的終結使用完之後,流已經操作完了,不能再繼續使用
    總結:
        -[] 能夠理解函數式編程相對於面向對象的優點
            Lambda -> 動態指令編程dynamic invoke
        -[] 能夠掌握Lambda表達式的標準格式
            (數據類型 參數名,數據類型 參數名) -> {方法體;return 返回值;}
        -[] 能夠掌握Lambda表達式的省略格式與規則
            a.數據類型無條件省略
            b.參數只有一個小時,小括號纔可以省略
            c.{}中只有一句代碼時,{}和;和return可以同時省略
        -[] 能夠使用Consumer<T>函數式接口
            public abstract void accept(T t); 消費
        -[] 能夠使用Predicate<T>函數式接口
            public abstract void test(T t); 判斷
        -[] 能夠理解流與集合相比的優點
        -[] 能夠掌握常用的流操作
                a.獲取流
                    集合:stream();
                    Stream.of(數組/可變參數);
                b.流的操作
                    filter 過濾操作
                    count 統計操作
                    limit 取前幾個
                    skip 跳過前幾個
                    foreach 逐一消費
                    concat 合併兩個流

            超綱:
                流的map方法
                ::方法引用
                collect 收集流的元素

            
        

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章