【Java】Lambda表达式 Stream流

Lambda表达式

        简化匿名内部类的代码写法(只能简化函数式接口的匿名内部类的写法形式)JDK8.0

        首先是接口,其次接口中有且仅有一个抽象方法的形式@FunctionalInterface注释校验

        面向对象编程:注重谁来做                函数式编程:注重做什么

Lambda表达式标准格式:(形式参数)  -> {代码块}

//匿名内部类写法
        goRuning(new Runing() {
            @Override
            public void run() {
                System.out.println("特斯拉飞驰");
            }
        });

//Lambda表达式写法
        goRuning(() -> {
            System.out.println("特斯拉飞驰");
            }
        );

//Lambda表达式简化
        goRuning(() -> System.out.println("特斯拉飞驰"));

        ():里面没有内容,可以看成是方法形参列表为空
        ->:用箭头指向要做的事情
        { }:代码块,可以看成是方法体中的内容

省略规则:
        参数类型可以省略,但是有多个参数的情况下,不能只省略一个
        如果参数有且仅有一个,那么小括号可以省略
        如果代码块的语句只有一条,可以省略大括号和分号,甚至是return

Lambda表达式与匿名内部类的区别

类型:

        匿名内部类:接口抽象类具体类

        Lambda表达式:接口

限制:

        匿名内部类:接口可以有一个或者多个抽象方法

        Lambda表达式:接口中只能一个抽象方法,可以@FunctionalInterface注释校验

实现原理:

        匿名内部类:编译之后,产生一个单独的.class字节码文件

        Lambda表达式:对应的字节码文件会在运行时动态生成

常用的函数式接口

Supplier接口(供应者)

        java.util.function.Supplier<T>接口

        它意味着"供给",对应的Lambda表达式需要对外提供一个符合泛型类型的对象数据

public class DemoSupplier {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "World";
        //1.匿名内部类的方式
        fun(new Supplier<String>() {
            @Override
            public String get() {
                return s1 + s2;
            }
        });
        System.out.println("---------");
        //2.使用lambda表达式的标准格式
        fun(() -> {
            return s1.toLowerCase() + s2.toLowerCase();
        });
        System.out.println("---------");
        //3.使用lambda表达式的简化格式
        fun(() -> s1.toUpperCase() + s2.toUpperCase());
    }

    //定义方法使用函数式接口Supplier作为参数
    public static void fun(Supplier<String> supplier) {
        //调用抽象方法get,获取字符串str
        //至于str的内容是什么以及如何获取,这里说不清楚
        String str = supplier.get();
        System.out.println(str);
    }
}

Consumer接口(消费者)

        java.util.function.Consumer<T>接口

        则正好相反,它不是生产一个数据,而是消费一个数据其数据类型由泛型参数决定

public class DemoConsumer {
    public static void main(String[] args) {
        String str = "Hello World";
        //1.匿名内部类的方式
        fun(str, new Consumer<String>() {
            @Override
            public void accept(String s) {
                //按照大写消费
                System.out.println(s.toUpperCase());
            }
        });

        //2.使用lambda表达式的标准格式
        fun(str, (String s) -> {
                //按照小写消费
                System.out.println(s.toLowerCase());
            }
        );

        //3.使用lambda表达式的简化格式
        fun(str, s -> System.out.println(s.length()));//长度
}

    //定义方法使用函数式接口Consumer作为参数
    public static void fun(String s, Consumer<String> consumer) {
        //调用抽象方法accept,处理字符串s
        //如何处理字符串s,说不清
        consumer.accept(s);
    }
}

Function接口(转换)

        java.util.function.Function<T,R>接口

        用来根据一个类型的数据得到另一个类型的数据前者称为前置条件,后者称为后置条件,有进有出转换

public class DemoFunction {
    public static void main(String[] args) {
        String sNum = "12345";
        //1.匿名内部类的方式
        fun(sNum, new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        });

        //2.使用lambda表达式的标准格式
        fun(sNum, (String s) -> {
            return Integer.parseInt(s);
        });

        //3.使用lambda表达式的简化格式
        fun(sNum, s -> Integer.parseInt(s));
    }

    /*
        定义方法,使用函数式接口Function作为参数
     */
    public static void fun(String strNum, Function<String, Integer> function) {
        //根据方法参数String类型的strNum
        //获取int数字num,至于如何根据String类型的strNum获取int数字num说不清
        int num = function.apply(strNum);
        System.out.println(num);
    }
}

Predicate接口(判断)

        java.util.function.Predicate<T>接口

有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用

public class DemoPredicate {
    public static void main(String[] args) {
        String ss = "HelloWorld";
        //1.匿名内部类的方式
        fun(ss, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //判断字符串长度是否大于5
                return s.length() > 5;
            }
        });

        //2.使用lambda表达式的标准格式
        fun(ss,(String s)->{
            //判断字符串是否包含"H"
            return s.contains("H");
        });

        //3.使用lambda表达式的简化格式
        fun(ss, s -> s.contains("h"));
    }

    /*
        定义方法,使用函数式接口Predicate作为参数
     */
    public static void fun(String str, Predicate<String> predicate) {
        //调用抽象方法test,根据字符串ss,获取boolean结果
        //至于根据字符串ss,如何获取boolean结果,说不清
        boolean result = predicate.test(str);
        System.out.println(result);
    }
}

Stream流

        JDK8,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念

目的:用于简化集合和数组操作的API

获取Stream流:

        创建一条流水线,并把数据放到流水线上准备进行操作

中间方法:

        流水线上的操作,一次操作完毕之后,还可以继续进行其他操作

终结方法:

        一个Steam流只能有一个终结方法,是流水线上的最后一个操作


创建Stream流

Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能

集合获取Stream流的方式

        可以使用Collection接口中默认方法stream()生产流

 数组获取Stream流的方式

public class DemoGetStream {
    public static void main(String[] args) {
        //1.获取List集合对象对应的Stream流对象
        List<String> list = new ArrayList<>();
        Stream<String> s1 = list.stream();

        //2.获取Set集合对象对应的Stream流对象
        Set<String> set = new HashSet<>();
        Stream<String> s2 = set.stream();

        //Map集合,内部没有直接定义stream方法获取Stream流对象
        //必须转换为单列集合Collection,然后获取Stream流对象
        Map<String, String> map = new HashMap<>();

        //3.获取Map集合键对应的Set集合对象对应的Stream流对象
        Stream<String> s3 = map.keySet().stream();

        //4.获取Map集合值对应的Collection集合对象对应的Stream流对象
        Stream<String> s4 = map.values().stream();

        //5.获取Map集合键值对对应的Set集合对象对应的Stream流对象
        Stream<Map.Entry<String, String>> s5 = map.entrySet().stream();


        String[] arr = {"张无忌", "张翠山", "张三丰", "张一元"};
        //6.获取数组对应的Stream流对象
        Stream<String> s6 = Stream.of(arr);

        //7.获取参数列表对应的Stream流对象
        Stream<String> s7 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");

        //8.java.util.Arrays工具类的静态方法stream,也可以把数组转换成Stream流对象
        Stream<String> s8 = Arrays.stream(arr);
        System.out.println(s8);
    }
}

中间操作方法(拼接)

中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程
在Stream流中无法直接修改集合、数组中的数据

public class DemoFilter {
    public static void main(String[] args) {
        //创建Stream流对象
        Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");

        //1.匿名内部类的方式
        /*
        Stream<String> s2 = s.filter(new Predicate<String>() {
            @Override
            public boolean test(String name) {
                //过滤出所有带娃的
                return name.contains("娃");
            }
        });

        */
        //2.使用lambda表达式的标准格式
        /*Stream<String> s2 = s.filter((String name) -> {
            return name.contains("娃");
        });*/

        //3.使用lambda表达式的简化格式
        Stream<String> s2 = s.filter(name -> name.contains("娃"));

        //遍历输出
        s2.forEach((String name)->{
            System.out.println(name);
        });
    }
}
public class DemoLimitSkip {
    public static void main(String[] args) {
        //创建Stream流对象
        Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");

        //步骤一: 只要前7个
        Stream<String> s2 = s.limit(7);

        //步骤二: 跳过前4个
        Stream<String> s3 = s2.skip(4);

        //遍历输出
        s3.forEach((String name)->{
            System.out.println(name);
        });
    }
}
public class DemoDistinct {
    public static void main(String[] args) {

        //创建Stream流对象
        Stream<String> s1 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃","爷爷", "蛇精", "蝎子精","大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃","爷爷", "蛇精", "蝎子精");
        Stream<String> s2 = s1.distinct();

        //遍历输出
        s2.forEach((String name)->{
            System.out.println(name);
        });
    }
}
public class DemoConcat {
    public static void main(String[] args) {

        //创建Stream流对象
        Stream<String> s1 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃");
        Stream<String> s2 = Stream.of("爷爷", "蛇精", "蝎子精");

        //把s1和s2合并
        Stream<String> s12 = Stream.concat(s1, s2);

        //遍历输出
        s12.forEach((String name)->{
            System.out.println(name);
        });
    }
}

终结操作方法(终结)

终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了

public class DemoForEach {
    public static void main(String[] args) {
        Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");
        //1.匿名内部类的方式
        /*s.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        //2.使用lambda表达式的标准格式
        /*s.forEach((String name)->{
            System.out.println(name);
        });*/

        //2.使用lambda表达式的简化格式
        s.forEach(name-> System.out.println(name));
    }
}
public class DemoCount {
    public static void main(String[] args) {
        //创建Stream流对象
        Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");

        //获取Stream流对象中的元素的个数
        long geShu = s.count();
        System.out.println("流对象中的元素个数: " + geShu);
    }
}

Collectors工具类提供了具体的收集方式

public class DemoStreamCollect {
    public static void main(String[] args) {
        //创建List集合对象,并添加数据
        List<Person> list = new ArrayList<>();
        Collections.addAll(list,
                new Person("张三", 18),
                new Person("李四", 38),
                new Person("王五", 28));

        //获取List集合对象的Stream流对象
        Stream<Person> s = list.stream();

        //利用map方法,把每个Person对象的年龄增加两岁后,存储到新的Stream流对象中
        Stream<Person> s2 = s.map(new Function<Person, Person>() {
            @Override
            public Person apply(Person person) {
                //把当前Person对象的年龄增加两岁
                person.setAge(person.getAge() + 2);
                return person;
            }
        });

        //利用collect方法把Stream流对象,转换成List集合对象
        list = s2.collect(Collectors.toList());

        //遍历新的List集合
        list.forEach((Person p)->{
            System.out.println(p);
        });
    }
}
public class DemoStreamMap {
    public static void main(String[] args) {
        // {new Person("张三", 18), new Person("李四", 38), new Person("王五", 28)};
        //创建List集合对象strList,存储数据类型String
        List<String> strList = new ArrayList<>();
        //添加多个字符串,每个字符串代表一个Person对象的信息
        Collections.addAll(strList,"张三:18","李四:38","王五:28");

        //需求: 把List集合对象strList中的每个字符串元素,转换成Person对象,存储到Stream流对象中

        //获取List对象strList对应的Stream流对象
        Stream<String> s1 = strList.stream();

        //使用Stream流对象s1调用map方法,把String元素处理成Person元素,存储新的Stream流对象中
        Stream<Person> s2 = s1.map(new Function<String, Person>() {
            @Override
            public Person apply(String personInfo) {
                //String personInfo: "张三:18"
                String[] array = personInfo.split(":");
                return new Person(array[0], Integer.parseInt(array[1]));
            }
        });

        //遍历存储Person对象的Stream流对象
        s2.forEach(new Consumer<Person>() {
            @Override
            public void accept(Person person) {
                System.out.println(person);
            }
        });
    }
}
补充知识排序Stream.Sorted

public class DemoStreamSorted {
    public static void main(String[] args) {
        //创建List集合对象,并添加数据
        List<Person> list = new ArrayList<>();
        Collections.addAll(list,
                new Person("张三", 18),
                new Person("李四", 38),
                new Person("王五", 28));

        //借助Stream流对象,对List集合中的Person对象按照age从小到大排序
        //获取List集合对象的Stream流对象
        Stream<Person> s = list.stream();

        //使用Stream流对象调用sorted方法,指定排序规则
        /*Stream<Person> s2 = s.sorted(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });*/

        //调用sorted方法,传递的是lambda表达式的简化格式
        Stream<Person> s2 = s.sorted((p1, p2) -> p1.getAge() - p2.getAge());

        //遍历
        s2.forEach(p-> System.out.println(p));
    }
}
补充Stream流转到数组中 Object[] toArray();
public class Demo1 {
    public static void main(String[] args) {
        Stream<String> s = Stream.of("10","20","30","40","50");
        Object[] objArray = s.toArray();
        System.out.println(Arrays.toString(objArray));
    }
}

Foreach补充知识点

单例Collection-Foreach遍历

public class DemoCollectionForeach {
    public static void main(String[] args) {
        //创建Collection集合
        Collection<String> coll = new ArrayList<>();
        //添加元素
        Collections.addAll(coll, "Hello", "Java", "C++", "Python");

        //单列和双列集合内部都有foreach方法,直接调用即可
        //单列集合调用forEach方法,传递匿名内部类对象
        coll.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

        //单列集合调用forEach方法,传递lambda表达式标准格式
        coll.forEach((String str)->{
            System.out.println(str);
        });

        //单列集合调用forEach方法,传递lambda表达式简化格式
        coll.forEach(str-> System.out.println(str));
    }
}

双列Map-Foreach遍历

public class DemoMapForeach {
    public static void main(String[] args) {
        //创建Map集合对象,并添加键值对
        Map<String, String> map = new HashMap<>();
        map.put("项羽", "虞姬");
        map.put("吕布", "貂蝉");
        map.put("刘备", "孙尚香");

        //Map集合有forEach方法
        //双列集合调用forEach方法,传递匿名内部类对象
        map.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String s, String s2) {
                System.out.println(s + "::::" + s2);
            }
        });

        //双列集合调用forEach方法,传递lambda表达式标准格式
        map.forEach((String key, String value) -> {
            System.out.println(key + "===" + value);
        });

        //双列集合调用forEach方法,传递lambda表达式简化格式
        map.forEach((key, value) -> System.out.println(key + "....." + value));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值