null在Java中带来的麻烦
我相信全部的Java程序猿必定都遇到过NullPointerException
,空指针在Java程序中是最多见的,也是最烦人的;它让咱们不少程序猿产生了根深蒂固的感受,全部可能产生空指针的地方都的加上if-else
检查,可是这带给咱们不少麻烦java
- Java自己是强类型的,可是null破坏了这个规则,它能够被赋值给任何对象
- Java的设计是让程序猿对指针无感知,可是null指针是个例外
- 它会是代码变得很臃肿,处处都充斥着
if-else
的空检查,甚至是多层嵌套,代码可读性降低 - null自己毫无心义,表示不了
无
前两点不须要特别的说明,后两点举个例子来讲明一下: 假如一我的拥有一个手机,每一个手机都有生成厂商,每一个厂商都会有个名字,用类表示的话:app
public class Person { private Phone phone; public Phone getPhone() { return phone; } } public class Phone { private Producer producer; public Producer getProducer() { return producer; } } public class Producer { private String name; public String getName() { return name; } }
在这个例子中,假如咱们须要取到手机生成厂商的名字函数
public String getPhoneProducerName(Person person) { return person.getPhone().getProducer().getName(); }
因为不必定每一个人都会有一个手机,全部在调用getProducer()
时可能会出现NullPointerException
。学习
一门设计语言原本就是来描述世界的,在这个事例中有的人有手机,有的人也可能没有手机,因此在调用person.getPhone()
返回的值就应该包含有和无这两种状况,如今经过返回null
来表示无,可是在调用getProducer()
却又会抛出异常,这样就不太符合现实逻辑;因此把null
来用来表示无
不合适ui
在遇到这种状况一般的作法是作null检查,甚至是每一个地方可能发生null指针的作检查。设计
public String getPhoneProducerName(Person person) { if (person.getPhone() == null) { return "无名字"; } if (person.getPhone().getProducer() == null) { return "无名字"; } return person.getPhone().getProducer().getName(); }
这里我已经试图在减小代码的层级,若是使用的是if-else
,代码的层级会更深,代码可读性降低。指针
Optional的简单介绍
吐槽了那么多现状的很差,如今能够祭出咱们的解决方案了 Optional
;千呼万唤始出来,犹抱琵琶半遮面;那Optional
究竟是个什么东西,咱们一块儿来逐步解开它的面纱。code
Optional
自己只是对对象的简单包装,若是对象为空,那么会构建一个空的Optional
;这样一来Optional
就包含了存在和不存在两个状况, 接下来能够看下上面的例子改过以后对象
public class Person { private Optional<phone> phone; public Optional<phone> getPhone() { return phone; } } public class Phone { private Producer producer; public Producer getProducer() { return producer; } } public class Producer { private String name; public String getName() { return name; } }
因为有的人可能没有手机,有的人有,因此Phone
须要用Optional
包装起来;手机自己必定会有生产的厂商,厂商必定会有一个名字,因此这两个不须要用Optional
包装起来。这里咱们会发现使用了Optional
会丰富代码的语义,让代码更加符合现实。blog
而当咱们在调用phone.getProducer().getName()
的时候不须要作null指针的检查,若是说在这里发生了NullPointerException
,说明这里数据自己是有问题的,不符合现实,就应该让问题暴露出来,而不是像上面的代码同样把问题掩盖。
Optional的经常使用方法使用
1. Optional的建立方法
Optional<person> empty = Optional.empty(); //申明一个空的Optional Optional<person> person = Optional.of(new Person()); //包装Person Optional<person> person2 = Optional.of(null); //不容许的操做,传入null 会抛出空指针异常 Optional<person> optionalPerson = Optional.ofNullable(null); //容许传null, 返回一个空的Optional
2. Optional值的获取方式
- map、flatMap 首先咱们从新定义一下Phone类,除了有生产厂商以外,还有个型号;
public class Phone { private String model; private Producer producer; public Producer getProducer() { return producer; } public String getModel() { return model; } }
当咱们须要获取到手机的型号的时候能够这样:
Optional<phone> optionalPhone = Optional.of(new Phone()); Optional<string> model = optionalPhone.map(Phone::getModel);
当咱们须要经过Person对象获取到Phone的型号是,会想到这样:
Optional<person> optionalPerson = Optional.of(new Person()); optionalPerson.map(Person::getPhone).map(Phone::getModel);
当咱们写出来的时候发现编译器不能经过。是由于Person::getPhone
返回的是一个Optional<phone>
,调用optionalPerson.map(Person::getPhone)
返回的就是Optional<optional<phone>>
,因此再.map
的就没法拿到手机型号,那如何可以让返回的结果不是Optional<optional<phone>>
,而是Optional<phone>
呢?
这里须要用到另外一个方法flatMap
。flatMap
和map
的区别,我在刚开始学习的时候,看到了网上的各类解释都很绕,看的很晕,最后直接打开源码来看,发现实现很简单,很容易理解,来看下源码:
public<u> Optional<u> map(Function<!--? super T, ? extends U--> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } } public<u> Optional<u> flatMap(Function<!--? super T, Optional<U-->> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }
map
方法在返回的时候会包装一层Optional
; flatMap
在返回的时候直接把函数的返回值返回了,函数的结果必须是Optional
;那么在前面的例子中咱们直接调用flatMap
返回的结果就是Optional<phone>
Optional<person> optionalPerson = Optional.of(new Person()); optionalPerson.flatMap(Person::getPhone).map(Phone::getModel);
- 取出
Optional
中的值对象:get、orElse、orElseGet、orElseThrow、ifPresent
- get() : 当你明确知道Optional中有值的话能够直接调用该方法,当Optional中没有值是该方法会抛出异常
NoSuchElementException
;因此当若是存在空值的话建议就不要调用该方法,由于这样和作null检查就没有区别了 - orElse(T other) : 提供一个默认值,当值不存在是返回这个默认值
- orElseGet(Supplier<!--? extends T--> other) : 当值不存在的时候会调用supper函数,若是说返回这个默认值的逻辑较多,那么调用这个方法比较合适;
- orElseThrow(Supplier<!--? extends X--> exceptionSupplier) : 当值为空时会抛出一个自定义的异常
- ifPresent(Consumer<!--? super T--> consumer) : 当值不为空是会调用
consumer
函数,若是值为空,那么这个方法什么都不作
- filter 过滤出知足条件的对象 假如咱们须要过滤出手机型号
IOS
的手机,并打印出型号,代码以下:
Person person = new Person(Optional.of(new Phone("IOS"))); Optional<person> optionalPerson = Optional.of(person); optionalPerson.flatMap(Person::getPhone) .filter(phone -> "IOS".equals(phone.getModel())) .map(Phone::getModel) .ifPresent(System.out::println);
总结
- 咱们讨论了null在Java程序的问题
- 介绍Java8中引入了
Optional
来表示有和无的状况以及初始化的方式 - 举例说明了
Optional
中常用到的方法
> 本人菜鸟,若是有任何写的不对的地方,欢迎在评论区指出</person></person></phone></u></u></u></u></phone></optional<phone></optional<phone></phone></person></string></phone></person></person></person></person></phone></phone>