Java8-Optional与null

对null进行处理

程序中经常需要对null情况进行处理,比如Course类中有一个List stuList属性,Student有一个name属性。
现在想要查看某个student的name属性的长度,不负责任(不处理null)的写法如下:

Course course = new Course("数学");
Student s0 = new Student("s0");
Student s1 = new Student(null);
Student s2 = null;
course.addStudent(s0, s1, s2);
int index = 1;
String name = course.getStuList().get(index).getName();  //index = 1或2都会抛出NullPointerException
System.out.println(name.length());

String name = course.getStuList().get(index).getName()这样写固然省事,但是当s2为null或者s1对象的name为null时,都会抛出大家熟悉的NullPointerException
所以需要使用大量的if...else语句对变量否为null进行判断。

int index = 1;
Student student = course.getStuList().get(index);
String errorMessage = "处理过程中无null";
String name = "";
if(student!=null) {
	name = student.getName();
	if(name!=null) {
		System.out.println(name.length());
	}else {
		errorMessage="student对象的name为null";
		
	}
}else {
	errorMessage="student对象为null";
}
sysout
System.out.println(errorMessage);

使用Optional处理null

null是一个特殊值,并不是一个类型,student.getName()可能返回null也可能返回String类型对象,这是两种不同的情况。
Java 8中引入了Optional类型来统一处理null与对应的类型。该类型为容器类型,可以包含某个类型的非空值与空值,所以可以对他们统一处理。
Optional基本用法如下:

Optional<Student> stuNullable = Optional.empty();//代表null的Optional对象
Student stu = new Student("s0");
System.out.println(stuNullable.isPresent());//false,判断里面是否存在Student对象
//Student student = stuNullable.get();//将抛出NoSuchElementException
Optional<Student> stuNotNull = Optional.ofNullable(stu);  //代表非空的Student,实际上将stu对象放入该Optional容器中
System.out.println(stuNotNull.isPresent());//true
Student student = stuNotNull.get(); //返回刚才装入的stu对象

其中 Optional.ofNullable(stu)的作用是:当stu为null时,返回Optional.empty(),否则返回包含stu对象的Optional对象(即,Optional.of(stu))。
到现在为止我们可以使用Optional来代替前面的对null值的直接处理,代码如下:

Course course = new Course("数学");
Student s0 = new Student("s0");
Student s1 = new Student(null);
Student s2 = null;
course.addStudent(s0, s1, s2);
int index = 1;
Student student = course.getStuList().get(index);
Optional<Student> stu = Optional.ofNullable(student);//将student放入Optioanl中进行处理
String errorMessage = "处理过程中无null";
String name = "";
if (stu.isPresent()) {
	Optional<String> nameOfNullable = Optional.ofNullable(stu.get().getName());
	if (nameOfNullable.isPresent()) {
		name = nameOfNullable.get();
		System.out.println(name.length());
	}else {
		errorMessage="student对象的name为null";
	}
}else {
	errorMessage="student对象为null";
}
System.out.println(errorMessage);

呃.....代码更复杂了。但至少让你不能忽略null值了。
再看看Optional中的其他方法ifPresentorElse

stu.ifPresent(e->System.out.println(e.getName()));//如果存在对象,则Optional中的包含的对象getName返回的值
Student defaultStudent = new Student("默认对象");
Student orElse = stu.orElse(defaultStudent); //如果存在对象直接返回该对象,否则返回defaultStudent对象

似乎无补于事。

Optional的map方法

对上面的代码可以使用map方法进行改造,如下所示:

int index = 0;
String errorMessage = "处理过程有null";
String name = "";
Optional<Course> courseNullable = Optional.ofNullable(course);
Optional<String> resultOptional = courseNullable.map(e->e.getStu(index)).map(e->e.getName());
String result = resultOptional.orElse(errorMessage);//resultOptional中可能为null,也可能有值。如果未null,则返回errorMessage。
System.out.println(result);

map方法入参为Function类型(可以将Optional中原来的类型转换成新的类型)。map(e->e.getStu(index))就是将Courset类型转换成Student类型map(e->e.getName())则是将Student类型转换成String类型。
map方法返回值为Optional类型,所以可以以链式风格map(e->e.getStu(index)).map(e->e.getName())取代上面复杂的if...else处理。

这个例子体现出了Optional的优越性,即可以通过其优雅的处理null值。
窃以为,相比较Optioanl带来的优越性,其语法还是有点复杂。建议先掌握其语法,这样至少看别人的相关代码的时候不会无所适从。

基础代码

class Student {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

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

        @Override
        public String toString() {
	    return "Student [name=" + name + "]";
        }

}

class Course {// 课程
	private String name;
	private List<Student> stuList;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void addStudent(Student... stus) {
		for (Student student : stus) {
			stuList.add(student);
		}
	}

	public Student getStu(int i) {
		return stuList.get(i);
	}

	public List<Student> getStuList() {
		return stuList;
	}

	public Course(String name) {
		this.name = name;
		stuList = new ArrayList<>();
	}

}

使用Optional改造Course

查看jdk文档,Optional的说明如下:

Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors.

即,Optional主要用于修饰方法的返回类型,来表示“没有结果”这个返回结果,还用在使用null作为返回类型容易导致出错的地方。
那么,我么可以使用Optional来改造Course的Student getStu(int i)代码:

public Student getStu(int i) {
		return stuList.get(i);
	}

该段代码主要有两个问题:

  1. i可能越界。
  2. get(i)返回的值可能为null。

改造后代码如下:

public Optional<Student> getStu(int i) {
	if (i >= stuList.size())
		return Optional.empty(); // 带代表null的Optional实例
	Student student = stuList.get(i);
	if (student == null)
		return Optional.empty();
	return Optional.of(student);
}

或者进一步简化,改造成这样:

public Optional<Student> getStu(int i) {
	if (i >= stuList.size())
		return Optional.empty(); 
	Student student = stuList.get(i);
	return Optional.ofNullable(student);
}

Optional.ofNullable方法可以处理入参为null的情况。其相关文档描述如下

Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.

定义测试方法如下

private static void getStuByIndex(Course course, int index) {
	Student stu0 = course.getStu(index).orElse(new Student("默认学生"));//如果为null,则返回“默认学生”对象
	System.out.println(stu0);
}

测试代码如下:

Course course = new Course("数学");
Student s0 = new Student("s0");
Student s1 = new Student(null);
Student s2 = null;
course.addStudent(s0, s1, s2);
getStuByIndex(course, 0);
getStuByIndex(course, 1);
getStuByIndex(course, 2);//s2为null
getStuByIndex(course, 3);//越界,返回Optional.empty()

输出:

Student [name=s0]
Student [name=null]
Student [name=默认学生]
Student [name=默认学生]

测试flatmap代码如下

Optional<Course> courseNullable = Optional.ofNullable(course);
Optional<String> r0 = courseNullable.flatMap(e->e.getStu(0)).map(Student::getName);
Optional<String> r1 = courseNullable.flatMap(e->e.getStu(1)).map(Student::getName);
Optional<String> r2 = courseNullable.flatMap(e->e.getStu(2)).map(Student::getName);
Optional<String> r3 = courseNullable.flatMap(e->e.getStu(3)).map(Student::getName);
System.out.println(r0);
System.out.println(r1);//Student的name属性为null,返回Optional.empty()
System.out.println(r2);//Student为null,返回Optional.empty()
System.out.println(r3);//数组越界,返回Optional.empty()

输出如下:

Optional[s0]
Optional.empty
Optional.empty
Optional.empty

对比以前的代码

Optional<String> resultOptional = courseNullable.map(e->e.getStu(index)).map(e->e.getName());

map(e->e.getStu(0))改成了flatMap(e->e.getStu(0))。这是因为改造前的e->e.getStu(0)返回的是Student对象,
而改造后返回的是Optional<Student>类型对象。观察改造后的代码段:

Optional<Optional<Student>> xa = courseNullable.map(e->e.getStu(2));
Optional<Student> xb = courseNullable.flatMap(e->e.getStu(2));

可以看到xa并不是我们想要的结果,而xb才是我们想要的结果。前面已经提到Optional相当于一个容器,那么Optional<Optional<Student>>
相当于容器中嵌套一个容器,在这里我们需要关注的是大容器里面的Optional<Student>类型对象。flatMap中的flat可以理解为平坦化,相当于
从嵌套的容器中取出自己真正想要的元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java8中的Optional类是一个容器对象,可以包含null或非null值。它提供了一种优雅的方式来处理null值,避免了NullPointerException异常的出现。Optional类可以用于返回值、方法参数和实例变量等场景中,使代码更加简洁、清晰和安全。使用Optional类可以使代码更加健壮,减少了代码中的null检查和异常处理,提高了代码的可读性和可维护性。 ### 回答2: Optional类是Java 8中新引入的一个类,它的主要作用是在避免NullPointerException的情况下将null返回给调用者。这个类是一个容器对象,它可以保存非空的对象,也可以保存空值(null)。 Optional类提供了通过判断一个对象是否为空来避免空指针异常的方式。它可以在代码中替换传统的null判断,这样可以更加方便地编写代码,并且可以使代码更加健壮。 在Java中,如果一个方法返回值为null,那么在调用该方法返回值的时候,会有可能抛出NullPointerException异常。而Optional类的出现可以帮助我们避免这种情况的出现,在调用Optional类的get()方法时,如果Optional类中保存的对象不为null,就会返回该对象,否则抛出一个NoSuchElementException异常。 Optional类还提供了一些方法来简化代码,比如orElse()方法,如果Optional类中保存的对象不为null,则返回该对象,否则返回指定的default值。还有ifPresent()方法,当Optional类中保存的对象不为null时,会执行指定的代码,否则不执行。 总之,Optional类是Java 8中一个很有用的类,它可以帮助我们更加方便地处理null值,避免空指针异常的出现,并且可以简化代码。但是需要注意的是,不应该滥用Optional类,因为它并不是完美的解决方案,有时候需要对null值进行特殊处理。 ### 回答3: Java 8在语言层面上增加了一个新的类:Optional。这是一个特殊的容器对象,可以包含一个null或非null的值。 Optional的目的是解决Java中的null引用问题。在Java中,如果一个变量被赋值为null,而我们试图调用该变量所对应的方法,那么就会出现NullPointerException异常。 使用Optional可以避免这种情况的发生。如果一个变量是Optional对象,那么我们必须显式地检查该对象是否包含非null的值,才能对其进行操作。这样,在我们试图调用该变量所对应的方法之前,就可以避免空指针异常的发生。 Optional类提供了很多方法来判断是否有值、获取值、如果没有值则返回默认值等等,使得我们可以更加方便地处理空值。 下面是一些Optional类提供的方法: 1. Optional.of(T value):创建一个包含非null值的Optional对象,如果T为null,则抛出NullPointerException异常。 2. Optional.ofNullable(T value):创建一个Optional对象,如果T为null,则该对象为空。 3. Optional.empty():创建一个空的Optional对象。 4. get():如果值存在,则返回该值,否则抛出异常。 5. orElse(T other):如果值存在,则返回该值,否则返回其他默认值。 6. isPresent():返回一个boolean类型的值,表示该Optional对象是否包含值。 7. ifPresent(Consumer<? super T> consumer):如果该Optional对象包含值,则对该值执行给定的操作。 在编写Java程序时,我们应该始终努力避免使用null值。使用Optional类,可以使得我们的代码更加健壮、可读性更强。但是,过多地使用Optional可能会导致代码过于冗长,所以在使用的过程中需要权衡利弊。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值