一文读懂java lamda表达式的用法,比如:Optional.ofNullable,ifPresent,orElse,forEach,filter,map,collect,distinct

1. 文章引言


今天,测试人员发现一个java.lang.NullPointerException异常,即空指针异常。

于是,通过接口排查,发现此前开发人员,使用java8 lamda表达式写的。

写的很漂亮,但没有做严谨的判断。

为了复现这个错误,我需要写个用来测试的Student类,如下代码所示:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    
    
  private String name;
  private String sex;
  private int age;

  public static Student getInstance() {
    
    
    Student student = new Student();
    student.setName("念兮为美");
    student.setAge(16);
    student.setSex("男");
    return student;
  }
  
  public static void main(String[] args) {
    
    
  }
}

我们在main方法中写如下代码:

public static void main(String[] args) {
    
    
    Student student = getInstance();
    Student student1 = getInstance();
    student.setName("张三");
    Student student2 = getInstance();
    List<Student> students = new ArrayList<>();
    students.add(student);
    students.add(student1);
    students.add(student2);
    students.add(null);

    // 只输出姓名
    Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
        .map(Student::getName)
        .forEach(t -> System.out.println(t));
  }

运行main方法,即报出如下错误:

在这里插入图片描述

因为students集合在添加第4个对象时,没有做出对象为空的判断。

所以,输出前3个姓名,第4个即报空指针异常。

2. Optional.ofNullable


Optional.ofNullable是判断对象不能为空,如果对象为容器的话,则无法判断容器中的对象是否为空,如下代码所示:

public static void main(String[] args) {
    
    
    Student student = getInstance();
    Student student1 = getInstance();
    student.setName("张三");
    Student student2 = getInstance();
    List<Student> students = new ArrayList<>();
    students.add(student);
    students.add(student1);
    students.add(student2);
    students.add(null);

    // 判断students集合是否为空,如果不为空,则执行,但无法判断集合中对象是否为空
    Optional.ofNullable(students).ifPresent(t -> System.out.println(t));
}

输出结果:

在这里插入图片描述

2.1 ifPresent


ifPresent表示如果存在值,则使用该值调用指定的使用者,否则不执行任何操作。

该值表示Optional.ofNullable(T value)中的value对象,比如本示例中的students对象,如下为ifPresent的源码:

/**
     * If a value is present, invoke the specified consumer with the value,
     * otherwise do nothing.
     *
     * @param consumer block to be executed if a value is present
     * @throws NullPointerException if value is present and {@code consumer} is
     * null
     */
    public void ifPresent(Consumer<? super T> consumer) {
    
    
        if (value != null)
            consumer.accept(value);
    }

2.2 orElse

  1. orElse表示如果Optional.ofNullable中的对象为空,则返回一个新的对象。
public static void main(String[] args) {
    
    
    // 断students集合是否为空,如果为空,orElse创建新的集合返回
    Student student3=new Student();
    student3.setName("新学生");
    //定义空集合
    List<Student> students1 = null;
    //创建orElse后的集合
    ArrayList<Student> objects = new ArrayList<>();
    objects.add(student3);
    Optional.ofNullable(students1).orElse(objects).forEach(t -> System.out.println(t));
    }

输出结果:

在这里插入图片描述

  1. orElseGet用的是Supplier接口返回的对象。

supplier接口就一个get方法,无入参,出参要和Optional的对象同类型。

在这里插入图片描述

  1. orElseThrow用的是Supplier接口返回的对象,这个对象必须要实现Throwable

supplier接口就一个get方法,无入参,出参要实现Throwable

在这里插入图片描述

3. forEach


相当于for,遍历集合。

上面的代码也演示过,如下代码再次演示:

System.out.println("forEach 遍历结果:");
students.forEach(t -> System.out.println("\t\t" + t));

System.out.println("for 遍历结果:");
for (Student student3 : students) {
    
    
  System.out.println("\t\t" +student3);
}

在这里插入图片描述

4. filter


filter用来过滤数据的,使用如下代码可以解决文章引言中的错误:

// 只输出姓名
Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
    .filter(Objects::nonNull)
    .map(Student::getName)
    .forEach(t -> System.out.println(t));

输出结果:

在这里插入图片描述

5. map


map表示后面的值替换前面的值,我们一般可以只获取对象中的属性值。

Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
     .filter(Objects::nonNull)
     .map(Student::getName)
     .forEach(t -> System.out.println(t));

输出结果:

在这里插入图片描述

6. collect


实现各种有用的减少操作,如将元素累积到集合中,汇总根据各种标准的元素,等等。

 String collect =
        Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
            .filter(Objects::nonNull)
            .map(Student::getName)
            .collect(Collectors.joining(","));
    System.out.println(collect);

输出结果:

在这里插入图片描述

collect也有如下如下用法:

 Map<String, Integer> collect1 =
        Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
            .filter(Objects::nonNull)
            .collect(Collectors.toMap(Student::getName, Student::getAge));
    collect1.forEach((name, age) -> System.out.printf("name -> %s, age -> %d\n", name, age));

在这里插入图片描述

但是报错了,为什么这样呢?因为mapkey不能重复。

我们上述代码:name作为key值,但出现了两个念兮为美,即key值重复了。

可以使用如下代码解决:

Map<String, Integer> collect1 =
        Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
            .filter(Objects::nonNull)
            .collect(
                Collectors.toMap(Student::getName, Student::getAge, (value1, value2) -> value2));
    collect1.forEach((name, age) -> System.out.printf("name -> %s, age -> %d\n", name, age));

在这里插入图片描述

7. distinct

distinct表示去重。

在之前的代码中,念兮为美每次都输出两次,我们可以使用distinct去重,如下代码所示:

  String collect1 =
        Optional.ofNullable(students).orElse(new ArrayList<>()).stream()
            .filter(Objects::nonNull)
            .map(Student::getName)
            .distinct()
            .collect(Collectors.joining(","));
    System.out.println(collect1);

输出结果:

在这里插入图片描述

8. 总结


java lamda表达式有很多知识点,需要自己去实践。

猜你喜欢

转载自blog.csdn.net/lvoelife/article/details/133927211
今日推荐