摘要
Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException)。它提供了可设置为空值(ofNullable)、值是否存在(isPresent)、值为空时取默认值(orElse)等方法,让我们在操作对象时可以优雅处理空值。
示例
1.empty()
通过empty创建一个空的Optional,此时get时会报错
2.get()
get()方法获取Optional值,如果为空时会报java.util.NoSuchElementException: No value present
System.out.println("-----Optional.empty-----");
Optional<String> optional=Optional.empty();
optional.get();
输出
-----Optional.empty-----
java.util.NoSuchElementException: No value present
3.of()
of()向Optional填充值,此时不能为空,为空时报错
System.out.println("-----Optional.off-----");
User emptyUser=null;
Optional<User> optional = Optional.of(emptyUser);
输出
-----Optional.off-----
java.lang.NullPointerException
4.ofNullable()
ofNullable()向Optional填充值,此时可为空
System.out.println("-----Optional.ofNullable-----");
User emptyUser=null;
Optional.ofNullable(emptyUser);
5.isPresent()
判断Optional值是否存在
System.out.println("-----Optional.isPresent-----");
Optional<String> optional= Optional.empty();
System.out.println(optional.isPresent());
输出
-----Optional.isPresent-----
false
该方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式:
System.out.println("-----Optional.isPresentLambda-----");
User user=new User(1,"小杨");
Optional<User> optional= Optional.of(user);
optional.ifPresent( u -> System.out.println("用户名:"+u.getName()));
输出
-----Optional.isPresentLambda-----
用户名:小杨
6.orElse()
orElse()如果有值则返回该值,否则返回传递给它的参数值
System.out.println("-----Optional.orElse-----");
User emptyUser=null;
User user=new User(1,"小杨");
User res= Optional.ofNullable(emptyUser).orElse(user);
System.out.println(toString(res));
输出
-----Optional.orElse-----
{“id”:1,“name”:“小杨”}
7.orElseGet()
有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果。
@Test
public void orElseGet(){
System.out.println("-----Optional.orElseGet-----");
User emptyUser=null;
User res= Optional.ofNullable(emptyUser).orElseGet(()->getDefaultUser());
System.out.println(toString(res));
}
private User getDefaultUser(){
System.out.println("创建默认用户");
User user=new User(0,"管理员");
return user;
}
输出
-----Optional.orElseGet-----
创建默认用户
{“id”:0,“name”:“管理员”}
orElse()与orElseGet()在值为空时没有区别,但是在有值时orElse仍然会运行创建orElse()中的对象
@Test
public void orElseGetAndOrElse(){
System.out.println("-----Optional.orElseGetAndOrElse-----");
User defUser=new User(1,"小杨");
System.out.println("Optional.orElse");
User user = Optional.ofNullable(defUser).orElse(getDefaultUser());
System.out.println(toString(user));
System.out.println("Optional.orElseGet");
User res= Optional.ofNullable(defUser).orElseGet(()->getDefaultUser());
System.out.println(toString(res));
}
private User getDefaultUser(){
System.out.println("创建默认用户");
User user=new User(0,"管理员");
return user;
}
输出
-----Optional.orElseGetAndOrElse-----
Optional.orElse
创建默认用户
{“id”:1,“name”:“小杨”}
Optional.orElseGet
{“id”:1,“name”:“小杨”}
8.orElseThrow()
对象为空的时候抛出异常
System.out.println("-----Optional.orElseThrow-----");
String res = (String)Optional.empty().orElseThrow( () -> new IllegalArgumentException("值为空"));
输出
-----Optional.orElseThrow-----
java.lang.IllegalArgumentException: 值为空
9.map()
对值调用作为参数的函数,然后将返回的值包装在 Optional 中。
System.out.println("-----Optional.map-----");
User user=new User(1,"小杨");
String userName=Optional.ofNullable(user).map(u->u.getName()).get();
System.out.println(userName);
输出
-----Optional.map-----
小杨
10.filter()
返回过滤结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional
System.out.println("-----Optional.filter-----");
System.out.println("-----name=小杨-----");
User user=new User(1,"小杨");
String res=Optional.ofNullable(user).filter(u->u.getName().equals("小杨")).map(u->u.getName()).orElse("用户不存在");
System.out.println(toString(res));
System.out.println("-----name=小张-----");
String res1=Optional.ofNullable(user).filter(u->u.getName().equals("小张")).map(u->u.getName()).orElse("用户不存在");
System.out.println(toString(res1));
输出
-----Optional.filter-----
-----name=小杨-----
“小杨”
-----name=小张-----
“用户不存在”
优雅处理NPE
1.传统NPE处理
private static String defaultPreUrl="http://127.0.0.1/preview/miss.jpg";
private static FileV1 file1=new FileV1(1,"测试文件",null,"http://127.0.0.1/file/test.pdf");
private static ResourceV1 resource1 = new ResourceV1(1,"测试资源",file1);
@Test
public void NPEV1(){
System.out.println("-----------传统NPE判断-----------");
String url=defaultPreUrl;
if (file1 != null) {
FileV1 file = resource1.getFile();
if (file != null) {
PreviewV1 preview = file.getPreview();
if (preview != null) {
url = preview.getUrl();
}
}
}
System.out.println(url);
}
class ResourceV1{
private Integer id;
private String name;
private FileV1 file;
public ResourceV1(Integer id, String name, FileV1 file) {
this.id = id;
this.name = name;
this.file = file;
}
//get set
}
class FileV1{
private Integer id;
private String name;
private PreviewV1 preview;
private String url;
public FileV1(Integer id, String name, PreviewV1 preview, String url) {
this.id = id;
this.name = name;
this.preview = preview;
this.url = url;
}
//get set
}
class PreviewV1{
private Integer id;
private String name;
private String url;
public PreviewV1(Integer id, String name, String url) {
this.id = id;
this.name = name;
this.url = url;
}
//get set
}
输出
-----------传统NPE判断-----------
http://127.0.0.1/preview/miss.jpg
2.通过Optional处理NPE
private static String defaultPreUrl="http://127.0.0.1/preview/miss.jpg";
private static FileV2 file2=new FileV2(1,"测试文件",null,"http://127.0.0.1/file/test.pdf");
private static ResourceV2 resource2 = new ResourceV2(1,"测试资源",file2);
@Test
public void NPEV2(){
System.out.println("-----------Optional NPE判断-----------");
String result = Optional.ofNullable(resource2)
.flatMap(ResourceV2::getFile)
.flatMap(FileV2::getPreview)
.map(PreviewV2::getUrl)
.orElse(Optional.of(defaultPreUrl)).get();
System.out.println(result);
}
class ResourceV2{
private Integer id;
private String name;
private FileV2 file;
public ResourceV2(Integer id, String name, FileV2 file) {
this.id = id;
this.name = name;
this.file = file;
}
public Optional<FileV2> getFile() {
return Optional.ofNullable(file);
}
public void setFile(FileV2 file) {
this.file = file;
}
//get set
}
class FileV2{
private Integer id;
private String name;
private PreviewV2 preview;
private String url;
public FileV2(Integer id, String name, PreviewV2 previewV2, String url) {
this.id = id;
this.name = name;
this.preview = preview;
this.url = url;
}
public Optional<PreviewV2> getPreview() {
return Optional.ofNullable(preview);
}
public void setPreview(PreviewV2 preview) {
this.preview = preview;
}
//get set
}
class PreviewV2{
private Integer id;
private String name;
private String url;
public PreviewV2(Integer id, String name, String url) {
this.id = id;
this.name = name;
this.url = url;
}
public Optional<String> getUrl() {
return Optional.ofNullable(url);
}
public void setUrl(String url) {
this.url = url;
}
//get set
}
输出
-----------Optional NPE判断-----------
http://127.0.0.1/preview/miss.jpg