一、前言

Optional是Java 8引入的一个容器类,它位于java.util包下。Optional类是一个可以为null的容器对象,用于解决空指针异常(NullPointerException)的问题。通过明确地使用Optional,程序可以更加清晰地表达一个值可能存在也可能不存在的情况,从而提高代码的健壮性和可读性。

二、使用场景

1.替换显式的null检查

在Java中我们常常需要手动检查一个对象是否为null,以避免空指针异常。如果我们使用Optional我们就可以将这些显式的null检查替换为更优雅、更表达性的代码。

重构前:

package com.example.springbootdemo.test;

public class NullTest {

    public static void main(String[] args) {
        String str = null;
        if (str != null) {
            System.out.println(str.length());
        } else {
            System.out.println("字符串对象为空");
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

重构后:

package com.example.springbootdemo.test;

import java.util.Optional;

public class NullTest {

    public static void main(String[] args) {
        String str = null;
        //接收str参数 如果str对象不为空就返回str 否则返回orElse中的对象
        String data = Optional.ofNullable(str).orElse("字符串对象为空");
        System.out.println(data);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

2.增强方法的返回值

   通过返回Optional而不是可能为null的值,我们可以增强方法的返回值类型,明确表明调用者需要处理值可能不存在的情况。

重构前:

package com.example.springbootdemo.test;

import java.util.Optional;

public class NullTest {

    public static void main(String[] args) {
        System.out.println(getData());
    }

    public static String getData() {
        return null;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

重构后:

package com.example.springbootdemo.test;

import java.util.Optional;

public class NullTest {

    public static void main(String[] args) {
        System.out.println(getOptionalData());
    }
    

    public static Optional<String> getOptionalData() {
        return Optional.empty();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

3.提高API的可用性

    当API的返回类型从可能为null的类型更改为Optional时,调用者可以更清晰地了解需要处理的情况,从而编写出更健壮的代码。

重构前:

package com.example.springbootdemo.test;


public class NullTest {

    public static void main(String[] args) {
        String data = null;
        if (data != null) {
            //处理逻辑
        }
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

重构后:

package com.example.springbootdemo.test;


import java.util.Optional;

public class NullTest {

    public static void main(String[] args) {
        String data = null;
        Optional<String> optional = Optional.ofNullable(data);
        if (optional.isPresent()) {
            String s = optional.get();
            System.out.println(s);
        }
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

4.在集合与流中使用Optional

  虽然Optional本身不是为集合设计的,但我们可以利用Java 8的流(Streams)和Optional来优雅地处理集合中的元素。

package com.example.springbootdemo.test;


import com.example.springbootdemo.domain.Student;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class NullTest {

    public static void main(String[] args) {
        List<Student> studentList1 = getStudentList();
        Optional<Student> optional = studentList1.stream().filter(s -> s.getAge() > 21).findFirst();
        optional.ifPresent(s -> System.out.println(s.getName()));
    }

    public static List<Student> getStudentList() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("aa", 20, "大一"));
        list.add(new Student("bb", 21, "大二"));
        list.add(new Student("cc", 23, "大三"));
        list.add(new Student("dd", 24, "大四"));
        list.add(new Student("ee", 21, "大二"));
        return list;
    }


}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

运行结果:

使用Optional重构和优化代码_Java

5.Optional与函数式编程

Optional是Java 8引入的函数式编程特性之一,它与Lambda表达式、方法引用、Stream等特性紧密相连。通过结合使用这些特性,我们可以编写出更加简洁、富有表达力的代码。

package com.example.springbootdemo.test;


import com.example.springbootdemo.domain.Student;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class NullTest {

    public static void main(String[] args) {
        List<Student> studentList1 = getStudentList();
        //如果没有找到,则返回默认值
        Student student = studentList1.stream().filter(s -> s.getAge() > 24).findFirst().orElse(new Student());
        System.out.println(student);
    }

    public static List<Student> getStudentList() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("aa", 20, "大一"));
        list.add(new Student("bb", 21, "大二"));
        list.add(new Student("cc", 23, "大三"));
        list.add(new Student("dd", 24, "大四"));
        list.add(new Student("ee", 21, "大二"));
        return list;
    }


}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

运行结果:

使用Optional重构和优化代码_Optional_02

6.性能考量

 虽然Optional的引入主要是为了改善代码的可读性和健壮性,但在某些情况下,它的使用可能会对性能产生影响。特别是在处理大量数据时,频繁地创建和销毁Optional对象可能会带来不必要的开销。

建议:

  • 在性能敏感的场景中,避免不必要的Optional包装和拆包。
  • 如果确定一个值永远不会为null,则直接使用普通类型而非Optional。
三、总结
  • 在方法签名中明确地表示返回值可能为null或不存在,并考虑使用Optional来替代显式的null检查。
  • 避免在方法的实现内部滥用Optional,特别是在没有必要将其暴露给调用者时。
  • 密切关注Java社区关于Optional的讨论和最佳实践的更新,以便及时调整自己的编码风格。