JDK8 新语法介绍(Lambda、Stream、Optional)

时间:2023-02-09 16:25:18

(目录)


lambda表达式

代码中的遇到的函数式接口(有且仅有一个抽象方法),可以用lambda来代替,比如MQ发消息,我们传统的做法:

jmsTemplate.send(
    new MessageCreator() {    
    @Override
        public Message createMessage(Session session) throws JMSException { 
            return session.createTextMessage(String.valueOf(id));
        }
});

用lambda实现:

jmsTemplate.send(session -> session.createTextMessage(String.valueOf(id)));

补充:

Java内置四大核心函数式接口 —— 理论知识

函数式接口 参数类型 返回类型 用途
**Consumer<T>**消费型接口 T void 对类型为T的对象应用操<br/>作,包含方法:<br/>void accept(T t)
**Supplier<T>**供给型接口 T 返回类型为T的对象,包<br/>含方法:T get();
**Function<T, R>**函数型接口 T R 对类型为T的对象应用操<br/>作,并返回结果。结果<br/>是R类型的对象。包含方 法:R apply(T t);
**Predicate<T>**断定型接口 T boolean 确定类型为T的对象是否<br/>满足某约束,并返回<br/>boolean 值。包含方法<br/>boolean test(T t);

stream流

1、类型转换1

​ 可以将一个类的对象集合中的某个属性生成新的集合。 比如一个学生类,学生包含学号、姓名、性别、手机号码、qq号。 场景:几个学生集合,将其中所有的学号抽取出来生成新的集合。原来的写法只有遍历这个学生集合,拿到他的学号属性添加到学号的集合中。代码如下:

List<String>studentNos = new ArrayList<String>();
        for (Student student : studentList) { 
            studentNos.add(student.getStudentNo());
        }

这样要不断的循环,效率也会低很多。java 8中写法:

List<String> studentNos = 
studentList.stream().map(Student::getStudentNo).collect(Collectors.toList());

2、类型转换2

将List转换为Map。数组的查找效率是O(n)。效率还是比较低的,我们可以把他转化为Map。在知道key的情况下,访问速度就变成了O(1)。速度提升了很多。 场景:学生的集合已经获取到,他的学号是主键,我现在想要找出学号为0001的学生的名字。java 8以前的写法:

for (Student student : studentList) {
    if ("0001".equals(student.getStudentNo())){
        System.out.println(student.getName());
    }
}

java 8的写法

Map<String, String> collect = studentList.stream()
.collect(Collectors.toMap(Student::getStudentNo, Student::getName));
System.out.println(collect.get("0001"));

这是取两个属性字段,当然也可以用对象本省作为value,提供了一个属性方法:Function.identity()。可以获取对象本身。

3、过滤

从一个数组中筛选出来一些数据。 场景:找出学生列表中所有性别为男的学生 java 8以前的写法:

List<Student>manList = new ArrayList<Student>();
for (Student student : studentList) {
    if (student.getSex().equals(1)){
        manList.add(student);
    }
}

java 8以后的写法有个filter方法

List<Student> collect1 = studentList.stream().filter(s -> s.getSex().equals(1)).collect(Collectors.toList());

在filter方法中返回的是boolean类型。这种方式速度也会快很多。

4、排序

按照类里面的某个属性进行排序 场景:按照学生的年龄进行排序倒序排序

stream写法:

studentList.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());

补充:默认的自然排序最好也讲解一下

5、去重

List<Student> collect2 = studentList.stream().distinct().collect(Collectors.toList());

也可以根据某一属性去重

studentList.stream()
           .collect(Collectors.collectingAndThen (Collectors.toCollection(() 
-> new TreeSet<>(Comparator.comparingLong(Student::getName))), ArrayList::new));

也可以求和、求最大值、求最小值。和去重类似

6、快速找到集合中想要匹配的数据

//是否存在学号为0001的人
boolean match = studentList.stream().anyMatch(detail -> "0001".equals(detail.getStudentNo()));

7、跳过或者获取

//跳过前面n个元素
List<Student> skipList = studentList.stream().skip(2).collect(Collectors.toList());
//取前n个元素
List<Student> limitList = studentList.stream().limit(2).collect(Collectors.toList());

8、补充 Collectors

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例

  • list.stream().collect(Collectors.toList());

  • 把流中元素收集到List

  • list.stream().collect(Collectors.toSet());

  • 把流中元素收集到Set

  • list.stream().collect(Collectors.toCollection(ArrayList::new));

    • 把流中元素收集到创建的集合
  • list.stream().collect(Collectors.counting());

  • 计算流中元素的个数

  • list.stream().collect(Collectors.summingInt(User::getAge));

    • 对流中元素的整数属性求和
  • list.stream().collect(Collectors.averagingInt(User::getAge));

  • 计算流中元素Integer属性的平均值

  • list.stream().collect(Collectors.summarizingInt(User::getAge));

  • 收集流中Integer属性的统计值。如:平均值

  • list.stream().collect(Collectors.groupingBy(User::getAge));

    • 根据某属性值对流分组,属性为K,结果为V
  • 最大值maxBy和最小值 minBy


Optional对象

java8 中的Optional是为了减少空指针异常的。

BigDecimal bigAbmout = 
Optional.ofNullable(paymentChange.getPaymentChangeMoney()).orElseGet(() -> BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP);

这段代码的意思是当ofNullable的值为null是,可以个bigAmount一个默认值为0而不是Null防止后续代码使用bigAmount的时候报空指针异常。 还有一个orElse方法,他与orElseGet的区别是,orElseGet传的是一个lambda表达式函数式接口。使用orElse可以写成如下

BigDecimal bigAbmout = 
Optional.ofNullable(paymentChange.getPaymentChangeMoney()).orElse(BigDecimal.ZERO);