jdk8新特性笔记(Optional)

 

方法描述
of把指定的值封装为Optional对象,如果指定的值为null,则抛出NullPointerException
empty创建一个空的Optional对象
ofNullable把指定的值封装为Optional对象,如果指定的值为null,则创建一个空的Optional对象
get如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException
orElse如果创建的Optional中有值存在,则返回此值,否则返回一个默认值
orElseGet如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值
orElseThrow如果创建的Optional中有值存在,则返回此值,否则抛出一个由指定的Supplier接口生成的异常
filter如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象
map如果创建的Optional中的值存在,对该值执行提供的Function函数调用
flagMap如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象
isPresent如果创建的Optional中的值存在,返回true,否则返回false
ifPresent如果创建的Optional中的值存在,则执行该方法的调用,否则什么也不做

 

用法:of,ofNullable,get,empty

//##### of #####
User user=new User("1","张三");
Optional<User> opt = Optional.of(user);
System.out.println(opt.get().getId());
结果:opt: 1

Optional<User> opt = Optional.of(null);//创建空的Optional会报空指针错误
结果:opt: java.lang.NullPointerException

//##### ofNullable #####
Optional<String> opt = Optional.ofNullable(null);//创建空的Optional也不会报错
Optional<String> opt2 = Optional.ofNullable("123");

//##### get ##### 
//如果我们创建的Optional对象中有值存在则返回此值,
//如果没有值存在,则会抛出 NoSuchElementException异常
Optional<String> opt = Optional.of("123");
System.out.println(opt.get());

//##### empty #####
Optional<String> opt = Optional.empty();//创建一个空的String类型的Optional对象
System.out.println(opt.get());
结果 : 访问 emptyOpt 变量的值会导致 NoSuchElementException

orElse,orElseGet

//##### orElse ##### 它的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值
Optional<String> stringOptional = Optional.of("1");
System.out.println(stringOptional.orElse("2"));
结果:1
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElse("2"));
结果:2

//##### orElseGet #####
//其行为略有不同。这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的
//Supplier(供应者) 函数式接口,并将返回其执行结果
Optional<String> stringOptional = Optional.of("1");
System.out.println(stringOptional.orElseGet(() -> "2"));
结果:1
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseGet(() -> "2"));
结果:2

orElse() 和 orElseGet() 的不同之处

乍一看,这两种方法似乎起着同样的作用。然而事实并非如此。我们创建一些示例来突出二者行为上的异同。

我们先来看看对象为空时他们的行为:

 

@Test
public void givenEmptyValue_whenCompare_thenOk() {
    User user = null
    logger.debug("Using orElse");
    User result = Optional.ofNullable(user).orElse(createNewUser());
    logger.debug("Using orElseGet");
    User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
}

private User createNewUser() {
    logger.debug("Creating New User");
    return new User("extra@gmail.com", "1234");
}

上面的代码中,两种方法都调用了 createNewUser() 方法,这个方法会记录一个消息并返回 User 对象。

代码输出如下:

Using orElse
Creating New User
Using orElseGet
Creating New User

由此可见,当对象为空而返回默认对象时,行为并无差异。

我们接下来看一个类似的示例,但这里 Optional  不为空:

@Test
public void givenPresentValue_whenCompare_thenOk() {
    User user = new User("john@gmail.com", "1234");
    logger.info("Using orElse");
    User result = Optional.ofNullable(user).orElse(createNewUser());
    logger.info("Using orElseGet");
    User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
}

private User createNewUser() {
    logger.debug("Creating New User");
    return new User("extra@gmail.com", "1234");
}

这次的输出:

Using orElse
Creating New User
Using orElseGet

这个示例中,两个 Optional  对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。

在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。

 

orElseThrow

//##### orElseThrow #####
@Test
public void OptionalTest() {
	User user=null;
	User result = Optional.ofNullable(user)
			.orElseThrow( () -> new IllegalArgumentException());
}

结果:java.lang.IllegalArgumentException

这里,如果 user 值为 null,会抛出 IllegalArgumentException

这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException

现在我们已经很好地理解了如何使用 Optional,我们来看看其它可以对 Optional 值进行转换和过滤的方法。

转换值:map

对stringOptional的值进行操作

@Test
public void OptionalTest() {
	Optional<String> stringOptional = Optional.of("zhangsan");
	System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("失败"));

	stringOptional = Optional.empty();
	System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("失败"));
}

结果:

ZHANGSAN
失败

flagMap

Optional<String> stringOptional = Optional.of("zhangsan");
System.out.println(stringOptional.flatMap(e -> Optional.of("lisi")).orElse("失败"));

stringOptional = Optional.empty();
System.out.println(stringOptional.flatMap(e -> Optional.empty()).orElse("失败"));

结果:

lisi
失败

map 和flagMap 的区别

map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。 
但flatMap方法中的lambda表达式返回值必须是Optionl实例

 

filter

如果创建的Optional中的值满足filter中的过滤条件,则返回包含该值的Optional对象

否则返回一个空的Optional对象

@Test
public void OptionalTest() {
	Optional<String> stringOptional = Optional.of("12345");
	System.out.println(stringOptional.filter(e -> e.length() >= 5).orElse("flase"));
	stringOptional = Optional.empty();//清空
	System.out.println(stringOptional.filter(e -> e.length() >= 5).orElse("flase"));
}

结果:

12345
false

ifPresent

ifPresent方法的参数是一个Consumer的实现类,Consumer类包含一个抽象方法,该抽象方法对传入的值进行处理,

只处理没有返回值。

@Test
public void OptionalTest() {
	Optional<String> stringOptional = Optional.of("zhangsan");
	stringOptional.ifPresent(e-> System.out.println("我被处理了。。。"+e));
}

结果

我被处理了。。。zhangsan

 

 

Optional  应该怎样用?

在使用 Optional 的时候需要考虑一些事情,以决定什么时候怎样使用它。

重要的一点是 Optional 不是 Serializable。因此,它不应该用作类的字段。

如果你需要序列化的对象包含 Optional 值,Jackson 库支持把 Optional 当作普通对象。也就是说,Jackson 会把空对象看作 null,而有值的对象则把其值看作对应域的值。这个功能在 jackson-modules-java8 项目中。

 

Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。

Optional 类有一个非常有用的用例,就是将其与流或其它返回 Optional 的方法结合,以构建流畅的API

我们来看一个示例,使用 Stream 返回 Optional 对象的 findFirst() 方法

@Test
public void OptionalTest() {
	List<User> users = new ArrayList<>();
	users.add(new User("1","name"));
	User user = users.stream().findFirst().orElse(new User("default", "default"));

	System.out.println(user.getId()+"   "+user.getName());
}

结果:1 name

@Test
public void OptionalTest() {
	List<User> users = new ArrayList<>();
	User user = users.stream().findFirst().orElse(new User("default", "default"));

	System.out.println(user.getId()+"   "+user.getName());
}

结果:default   default

实例:

//优化前
public static String getChampionName(Competition comp) throws IllegalArgumentException {
    if (comp != null) {
        CompResult result = comp.getResult();
        if (result != null) {
            User champion = result.getChampion();
            if (champion != null) {
                return champion.getName();
            }
        }
    }
    throw new IllegalArgumentException("The value of param comp isn't available.");
}

//优化后
public static String getChampionName(Competition comp) throws IllegalArgumentException {
    return Optional.ofNullable(comp)
            .map(c->c.getResult())
            .map(r->r.getChampion())
            .map(u->u.getName())
            .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
}

 

总结

Optional 是 Java 语言的有益补充 —— 它旨在减少代码中的 NullPointerExceptions,虽然还不能完全消除这些异常。

它也是精心设计,自然融入 Java 8 函数式支持的功能。

总的来说,这个简单而强大的类有助于创建简单、可读性更强、比对应程序错误更少的程序。

 

 

参考:https://www.cnblogs.com/zhangboyu/p/7580262.html

           https://blog.csdn.net/zknxx/article/details/78586799

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值