Java8中Optional的通常用法(我们常常忘记判空,NullPointerExceptions)

前文
程序中异常NullPointerExceptions,通常我们的代码会遇见如此的错误,很明显空指针异常错误,必定是哪里缺少判空操作
我们这样做

// Life before Optional
    private void Method(User user){
        if (user != null) {//如此判断,确实简单明了,
        //do something
        }
    }

也可能我们这样判断Util.isNotEmpty(user)或者ObjectUtil.isNotEmpty(user),其实都可以,没毛病
我们偶尔会忘记判空,这就会导致报错
java8之后使用Optional,实话看起来可能抽象了一些,代码品质可以提升一些档次,环境所需要,卷起来没错的

Optional

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。
以下介绍常用方法
创建一个Optional类

1static <T> Optional<T> empty()
返回空的 Optional 实例。
// Creating an empty optional
Optional<String> empty = Optional.empty();
System.out.println(empty);
====Optional.empty

2static <T> Optional<T> of(T value)
返回一个指定非null值的Optional// Creating an optional using of
String name = "java";
Optional<String> opt = Optional.of(name);
 System.out.println(opt);
===Optional[java]

3static <T> Optional<T> ofNullable(T value)
如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional// Possible null value

 Optional<String> optional = Optional.ofNullable(name());
 System.out.println(optional );

  private  String  name(){

  String name = "Java";

  return (name.length() > 5) ? name : null;

 }
name="java"====Optional.empty
name="javawww"====Optional[Javawww]

布尔值

boolean isPresent()
如果值存在则方法会返回true,否则返回 false。
···
//ispresent
Optional optional = Optional.of("javaone");
if (optional.isPresent()){
//Do something, normally a get
System.out.println("存在")
}
===存在

ifPresent(Consumer<? super T> consumer)
void ifPresent(Consumer<? super T> consumer)
如果值存在则使用该值调用 consumer , 否则不做任何事情。


//ifpresent

Optional<String> optional1 = Optional.of("javaone");
optional1.ifPresent(s -> System.out.println(s.length()));
====7

T get()
如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException

//get
Optional<String> optional = Optional.of("javaone");
if (optional.isPresent()){ 
  String value = optional1.get();
  System.out.println(value )

}
====javaone

T orElse(T other)
如果存在该值,返回值, 否则返回 other。

 //orElse
 String nullName = null;
 String name = Optional.ofNullable(nullName).orElse("default_name");
 System.out.println(name )
 =====default_name

T orElseGet(Supplier<? extends T> other)

如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。

  //orElseGet
  String name = Optional.ofNullable(nullName).orElseGet(() -> "john");
 System.out.println(name )
 ===john

注意:
a)不要将其用作类中的字段,因为它不可序列化
b)不要将其用作构造函数和方法的参数,因为这会导致不必要的复杂代码。
User user = new User(“哈哈哈”, “12345678”, Optional.empty());
其他方法请自行去看W3C传送门
感谢借鉴学习传送门

说一说通常在代码里面如何使用:
1、创建 Optional 实例

Optional<User> opt = Optional.ofNullable(user);

2、访问 Optional 对象的值

opt.ifPresent( u -> assertEquals(user.getEmail(), u.getEmail()));

3、返回值

User result = Optional.ofNullable(user).orElseGet( () -> user2);

4、orElse() 和 orElseGet() 的不同之处
当对象为空而返回默认对象时,行为并无差异。
两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。
在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。
5、返回异常
T orElseThrow(Supplier<? extends X> exceptionSupplier)
如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
Optional 还定义了 orElseThrow() API —— 它会在对象为空的时候抛出异常,而不是返回备选的值

  User result = Optional.ofNullable(user)
      .orElseThrow( () -> new IllegalArgumentException());

这里,如果 user 值为 null,会抛出 IllegalArgumentException。
这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException。
6、转换值
Optional map(Function<? super T,? extends U> mapper)
如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。

   String email = Optional.ofNullable(user)
      .map(u -> u.getEmail()).orElse("default@gmail.com");

map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。这就使对返回值进行链试调用的操作成为可能 —— 这里的下一环就是 orElse()。

相比这下,flatMap() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。

下面的操作中,我们给 User 类添加了一个方法,用来返回 Optional:

public class User {    
    private String position;
    public Optional<String> getPosition() {
        return Optional.ofNullable(position);
    }

    //...
}

既然 getter 方法返回 String 值的 Optional,你可以在对 User 的 Optional 对象调用 flatMap() 时,用它作为参数。其返回的值是解除包装的 String 值:

String position = Optional.ofNullable(user)
  .flatMap(u -> u.getPosition()).orElse("default");

7、过滤值

Optional filter(Predicate<? super predicate)
如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。

来看一个根据基本的电子邮箱验证来决定接受或拒绝 User(用户) 的示例:

    Optional<User> result = Optional.ofNullable(user)
      .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));

如果通过过滤器测试,result 对象会包含非空值。
链式:

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}
优化为:
public class User {
	 private Address address;	   

		public Optional<Address> getAddress() {
	        return Optional.ofNullable(address);
	    }

		public void setAddress(Address address) {
			this.address = address;
		}
		
}
public class Address {
	 private Country country;

	    public void setCountry(Country country) {
		this.country = country;
	}

		public Optional<Country> getCountry() {
	        return Optional.ofNullable(country);
	    }
}
public class Country {
	 private String isocode ;  
	    public Optional<String> getIsocode() {
	        return Optional.ofNullable(isocode);
	    }
		public void setIsocode(String isocode) {
			this.isocode = isocode;
		}

}

@Test
public void whenChaining_thenOk() {
    User user = new User("anna@gmail.com", "1234");

    String result = Optional.ofNullable(user)
      .flatMap(u -> u.getAddress())
      .flatMap(a -> a.getCountry())
      .map(c -> c.getIsocode())
      .orElse("default");

    assertEquals(result, "default");
}
上面的代码可以通过方法引用进一步缩减:

String result = Optional.ofNullable(user)
				  .flatMap(User::getAddress)
				  .flatMap(Address::getCountry)
				  .flatMap(Country::getIsocode)
				  .orElse("default");
测试:
	public static void main(String args[]) {
	    User user = new User();	
	    Address a=new Address();
	    Country c=new Country();
	    c.setIsocode(null);
	    a.setCountry(c);
	    user.setAddress(a);
	    
		String result = Optional.ofNullable(user)
				  .flatMap(User::getAddress)
				  .flatMap(Address::getCountry)
				  .flatMap(Country::getIsocode)
				  .orElse("default");
		System.out.print(result);

	}
==== c.setIsocode(null)=null-----default
c.setIsocode("666")=null-----666

感谢借鉴学习传送门

以上是整理学习的,感谢借鉴,只是java8的学习,java9听说做了一些改变可自行学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值