JDK8中的重要的新特性之Lambda 表达式&函数式接口

1. 方法引用

特殊的lambda表达式,它是对lambda表达式的一种简写方式。

1.1 方法引用的由来

 如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:---方法引用。::

public class Test {
    public static void main(String[] args) {
        fun(Test::sum);
    }
    public static void fun(Consumer<int[]> consumer){
        int[] arr = {1,2,3,4,5};
        consumer.accept(arr);
    }

    public static void sum(int[] arr){
        int sum = 0;
        for (int i : arr) {
            sum+=i;
        }
        System.out.println("结果为:" + sum);
    }
}

1.2 方法引用的类型

 方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用

1.3 静态方法引用

(args)->类名.静态方法(args). 当lambda表达式中方法体,只有一条语句,而这条语句是类名.静态方法。而静态方法的参数和lambda的参数一致时。

类名::静态方法;

1.4 实例方法引用

(args) -> inst.instMethod(args)

实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用。

首先创建一个Student实体类

public class Student {
    private String name;
    private Integer age;


    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public Integer getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(Integer age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

实例引用的案例代码

public class Test01 {
    public static void main(String[] args) {
        Student s = new Student("邵一凡", 19);

        //通过内置函数接口,返回对象的名称
//        fun(()->s.getName());
        fun(s::getName);//使用实例方法引用

//        Function<Student,String> function = (t)->{return t.getName();};//有参有返回值
        Function<Student,String> function = Student::getName;//有参有返回值
        String apply = function.apply(s);
        System.out.println(apply);//这个使用对象方法引用
    }

    public static void fun(Supplier<String> supplier) {
        String s = supplier.get();
        System.out.println(s);
    }
}

1.5 对象方法引用

lambda: (inst,args)->inst.普通方法(args): -------->类名::普通方法

若Lambda参数列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数时,可以使用对象方法引用。

public class Test02 {
    public static void main(String[] args) {
        //判断两个字符串是否相等

        //Lambda表达式
        fun((s1,s2)->{return s1.equals(s2);});
        //使用对象方法引用写
        fun(String::equals);
    }
    public static void fun(BiFunction<String,String,Boolean> booleanBiFunction){
        Boolean apply = booleanBiFunction.apply("hello", "hello");
        System.out.println(apply);
    }
}

1.6 构造方法引用

(args) -> new 类名(args)------构造方法引用: 类名::new

public class Test03 {
    public static void main(String[] args) {
//        Supplier<Student> supplier =()->new Student();
//        Student student = supplier.get();
//        System.out.println(student);

        Supplier<Student> supplier =Student::new;//使用了构造方法引用
        Student student = supplier.get();
        System.out.println(student);

        BiFunction<String,Integer,Student> biFunction = (s,a)->{return new Student(s,a);};
        Student s = biFunction.apply("邵一凡", 19);
        System.out.println(s);
    }
}

2. Stream

java8中的两个重大改变,一个是Lambda表达式,另一个就是Stream API表达式。  Stream是Java8中处理集合的关键抽象概念,他可以对集合进行非常复杂的查找、过滤、筛选等操作。

2.1 为什么使用stream流

  当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:

一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,成俊杰,张三丰
需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据

public class Test {
    public static void main(String[] args) {
//        一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,成俊杰,张三丰

//        需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
        List<String> list=new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("程俊杰");
        list.add("张三丰");

        //1.拿到所有姓张的
        List<String> newList01=new ArrayList<>();
        for(String n:list){
            if(n.startsWith("张")){
                 newList01.add(n);
            }
        }

        //2.拿到名字长度为3个字的
        List<String> newList02=new ArrayList<>();
        for(String n:newList01){
             if(n.length()==3){
                 newList02.add(n);
             }
        }

        //3.打印这些数据
        for(String s:newList02){
            System.out.println(s);
        }


    }
}

分析:

循环遍历的弊端

这段代码中含有三个循环,每一个作用不同:

  1. 首先筛选所有姓张的人;

  2. 然后筛选名字有三个字的人;

  3. 最后进行对结果进行打印输出。

每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。

那Stream能给我们带来怎样更加优雅的写法呢?

Stream初体验

public class Test01 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张三");
        list.add("程俊杰");
        list.add("张三丰");

        list.stream().filter(t->t.startsWith("张")).filter(t->t.length()==3).forEach(System.out::println);
    }
}

2.2 Stream流的原理

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

2.3 步骤

(1)获取Stream流对象

(2) 中间操作---返回类型还是Stream流对象。

(3)终止操作---不在是Stream流对象

2.4 获取Stream流对象的方式

(1) 通过集合对象调用stream()

(2)通过Arrays获取stream流对象

(3)通过Stream流里面of方法

public class Test02 {
    public static void main(String[] args) {
        //通过集合对象调用stream()
        ArrayList<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.stream().forEach(System.out::println);

        //通过使用Arrays工具类
        String[] arr = {};
        Stream<String> stream = Arrays.stream(arr);

        //通过Stream类
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
        //以上的都是串行流

        System.out.println("~~~~~~~~~~~~~~~~~~~");
        Stream<String> stringStream = list.parallelStream();//并行流
        stringStream.forEach(System.out::println);
    }
}

2.5 Stream流的api方法

举个简单的例子:

假设有一个Person类和一个Person列表,现在有两个需求:1)找到年龄大于18岁的人并输出;2)找出所有中国人的数量。

@Data
class Person {
    private String name;
    private Integer age;
    private String country;
    private char sex;

    public Person(String name, Integer age, String country, char sex) {
        this.name = name;
        this.age = age;
        this.country = country;
        this.sex = sex;
    }
}
public class Test {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("欧阳雪",18,"中国",'F'));
        personList.add(new Person("Tom",24,"美国",'M'));
        personList.add(new Person("Harley",22,"英国",'F'));
        personList.add(new Person("向天笑",20,"中国",'M'));
        personList.add(new Person("李康",22,"中国",'M'));
        personList.add(new Person("小梅",20,"中国",'F'));
        personList.add(new Person("何雪",21,"中国",'F'));
        personList.add(new Person("李康",22,"中国",'M'));
        //1. 年龄大于18  filter:过滤掉不满足条件的元素.  forEach:输出元素. ---如果没有终止函数,那么中间函数的代码不会被执行。
        personList.stream(). filter(item->{
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~");
            return item.getAge()>18;
        }).forEach(System.out::println);

        //2. 找出中国人  并统计个数: count()
        long count = personList.stream().filter(item -> item.getCountry().equals("中国")).count();
        System.out.println("中国人:"+count);
    }
}

(2)找出年龄最大和最小

Person person = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge()).get();
        Person person1 = personList.stream().min((o1, o2) -> o1.getAge() - o2.getAge()).get();
        System.out.println("年龄最大的:" + person);
        System.out.println("年龄最小的:" + person1);

(3)map-->

会把集合中的元素转化成另一种类型

 

//map的使用
        //personList.stream().filter(item->item.getCountry().equals("中国")).map(item->item.getName()).forEach(System.out::println);
        personList.stream().filter(item->item.getCountry().equals("中国")).map(item->new P(item.getName(), item.getAge())).forEach(System.out::println);
public class Test04 {
    public static void main(String[] args) {
        //整数数组每个元素+3
        List<Integer> list = Arrays.asList(1, 17, 27, 7);
        list.stream().map(item->item+3).forEach(System.out::println);

        List<String> list2=Arrays.asList("hello","world","java","spring","springmvc");
        //字符串大写
        list2.stream().map(String::toUpperCase).forEach(System.out::println);
    }
}

(4)收集 collect

把处理过的集合搜集成新的集合。

 List<Person> personList = new ArrayList<>();
        personList.add(new Person("小梅",24,"中国",'F'));
        personList.add(new Person("欧阳雪",18,"中国",'F'));
        personList.add(new Person("Tom",24,"美国",'M'));
        personList.add(new Person("Harley",22,"英国",'F'));
        personList.add(new Person("向天笑",20,"中国",'M'));
        personList.add(new Person("李康",22,"中国",'M'));
        personList.add(new Person("Tom",21,"中国",'F'));
        personList.add(new Person("李康",22,"中国",'M'));

        //把Person-年龄大于20人--里面名称----新的集合。
        List<String> collect = personList.stream().filter(item -> item.getAge() > 20).map(item -> item.getName()).collect(Collectors.toList());
        System.out.println(collect);

(5)sorted排序

//sorted排序
        List<Person> collect1 = personList.stream().sorted(((o1, o2) -> o1.getAge() - o2.getAge())).collect(Collectors.toList());
        System.out.println(collect1);

(6) reduce规约

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

 

 整型集合: -----请求。[1,2,3,4,5]=

public class Test05 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Integer integer = list.stream().reduce((t1, t2) -> t1 + t2).get();
        System.out.println(integer);
    }
}

(7)查询第一个findFirst

//查询第一个findFirst
        Optional<Person> first = personList.stream().filter(item -> item.getAge() >= 18 && item.getAge() <= 20).findFirst();
        System.out.println(first.get());

(9)去重、合并(distinct、skip、limit)

流也可以进行合并、去重、限制、跳过等操作。

public class Test06 {
    public static void main(String[] args) {
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };

        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);

        //去重操作
        /*List<String> collect = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        System.out.println(collect);*/
        //限制
        /*List<String> collect = Stream.concat(stream1, stream2).limit(3).collect(Collectors.toList());
        System.out.println(collect);*/
        //跳过
        List<String> collect = Stream.concat(stream1, stream2).distinct().skip(3).collect(Collectors.toList());
        System.out.println(collect);

    }
}

(10)匹配  anyMatch()   allMatch()  noMatch()

//匹配
        List<String> collect = Stream.concat(stream1, stream2).collect(Collectors.toList());
        boolean d = collect.stream().anyMatch(item -> item.equals("a"));
        System.out.println(d);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值