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 收集流的元素

            
        

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