Java 8新增的类-Optional

Java 8新增的类-Optional

Optional作用

Java8中新增了Optional类,Optional类相当于一个容器,这个容器可以包含一个null,也可以包含任何非null的对象。
这个类有两个作用(目的):

  1. 让消除代码中的NullPointerExecption的代码更优雅
  2. 处理对象为null,不为null的情况下的代码变得更简洁

按照功能分类Optional类的API

Optional类的Api按照功能,可分为以下几类:
创建Optional实例的api,包括empty()of()ofNullable(),返回的是一个Optional实例
Optaional中的value为null时,做什么的api,包括orElse()orElseGet()orElseThrow(),返回值是Optional中的vlaue
Optaional中的value不为null时,做什么的api,包括ifPresent()map()flatMap(),其中ifPresent()不返回任何值,map()flatMap()返回一个新的Optional对象
其它分类get()isPresent()filter()

Optional在实际中的应用

getListName()返回名字列表。如果listnull,则创建一个empty list返回,否则就返回list。使用了Optioanal中的orElse()方法来替代传统的if..else..,让代码看起来更加简洁。

    /**
     * 返回名字列表
     *
     * @return
     */
    @Test
    public List<String> getListName() {
        /*Java8之前的写法*/
        /*        
        List list = null;
        if (list == null) {
            return Collections.emptyList();
        } else {
            return list;
        }
        */

        /*Java8 Optional写法*/
        List<String> list = null;
        return Optional.of(list).orElse(Collections.emptyList());
    }

nameFormatDemo()名字首字母大写,如果name!=null则首字母转换为大写,如果name==null,则赋予no name值。

/**
     * 名字首字母大写
     */
    @Test
    public void nameFormatDemo() {
        final String DEFAULT_NAME = "no name";
        /*Java8之前的写法*/
        String name = "tom";
        if (name != null) {
            name = name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
        }else{
            name = DEFAULT_NAME;
        }
        System.out.println(String.format("Java8之前的写法,name:%s", name));

        /*Java8 Optional写法*/
        name = "tom";
        //name = null;
        Optional<String> nameOptional = Optional.ofNullable(name);
        name =  nameOptional.map(value -> value.substring(0, 1).toUpperCase() + value.substring(1, value.length())).orElse(DEFAULT_NAME);
        System.out.println(String.format("Java8 Optional写法,name:%s", name));
    }

printName()打印名字到控制台。name!=null则打印name到控制台,否则什么也不做。ifPresent()的作用是Optional中的value为null时,执行传递函数,否则什么也不做。

      /**
     * 打印名字到控制台
     */
    @Test
    public void printName(){
        String name = "Tom";
        /*Java8之前的写法*/
        if (name != null) {
            System.out.println(String.format("name:%s",name));
        }
        
        /*Java8 Optional写法*/
        Optional.ofNullable(name).ifPresent(value -> System.out.println(String.format("name:%s",value)));
    }

使用Optional注意事项

使用这个类需要注意以下几点:

  1. Optional不能作为字段或方法参数的类型,这个类只是一个工具类
  2. Optional 类型不可被序列化, 用作字段类型会出问题的
  3. Optional中的value是只读的,Optional没有提供API来修改value
  4. 调用Optional.get()之前,可以不用事先使用isPresent()方法检查当前Optional包含的value是否可用。因为Optional中的value==null时,get()方法会抛出异常
  5. Optional类没有什么难点,多看几遍源码就懂了

Optional使用示例

package com.zhangxy.optional;

import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.ToStringBuilder;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * Java8中新增了Optional类
 * @author zhangxy
 * @credte 2020-06-16 20:46
 */
public class OptionalTest {

    @Test
    public void emptyDemo() {
        Optional<Object> empty = Optional.empty();
        System.out.println(empty);//=>Optional.empty
    }

    /**
     * of(T value):用于给Optional实例中的value属性赋值,如果传递的vlaue==null将会抛出NullPointerException
     */
    @Test
    public void foDemo() {
        Optional<String> optional = Optional.of("小明");
        System.out.println("optional toString:" + optional);//=>myName is present:Optional[小明]

        Optional<String> nullOptional = Optional.of(null);//=>throw java.lang.NullPointerException
    }

    /**
     * ofNullabel(T value):作用同of(T value)相同,不同的是,如果传递的value==null不会抛出任何异常,返回一个empty的Optional实例
     */
    @Test
    public void ofNullable() {
        Optional<String> optional = Optional.ofNullable("小明");
        System.out.println("optional toString:" + optional);//=>myName is present:Optional[小明]

        Optional<String> nullOptional = Optional.ofNullable(null);
        System.out.println("optional toString:" + nullOptional);//=>optional toString:Optional.empty
    }

    /**
     * get():获取Optional实例中的value,如果vlaue==null,会抛出java.util.NoSuchElementException: No value present异常
     */
    @Test
    public void getDeom() {
        Optional<String> optional = Optional.of("小明");
        String myName = optional.get();
        System.out.println(String.format("myName:%s", myName));//=>myName:小明

        optional = Optional.empty();
        myName = optional.get();
        System.out.println(String.format("myName:%s", myName));//=>java.util.NoSuchElementException: No value present
    }

    /**
     * isPresent():用于判断Optional实例中value值是否为null,true表示不为null,否则为null
     */
    @Test
    public void isPresentDemo() {
        Optional<String> myName = Optional.empty();
        System.out.println("myName is present:" + myName.isPresent());//=>false

        myName = Optional.of("zhangxy");
        System.out.println("myName is present:" + myName.isPresent());//=>true

        myName = Optional.ofNullable(null);
        System.out.println("myName is present:" + myName.isPresent());//=>false
    }

    /**
     * ifPresent():如果Optional实例的vlaue!=null,则执行Consumer实例的accept(),否则什么也不执行
     * 相当于:
     * if(value!=null){
     *      //做一些操作,尤其是这些操作的代码较多时,这样写会显得代码更简洁写
     * }else{
     *      //什么也不做
     * }
     */
    @Test
    public void ifPresentDemo() {
        Optional<String> optional = Optional.of("ABC");
        optional.ifPresent(value -> System.out.println(String.format("value:%s", value)));//=>value:ABC

        optional = Optional.empty();
        optional.ifPresent(value -> System.out.println(String.format("value:%s", value)));//什么也不输出
    }

    /**
     * filter(Predicate predicate):根据Predicate实例的test()返回的值为true则返回当前Optional对象,否则返回一个empty的Optional对象
     * 相当于,满足过滤条件返回当前Optional对象,否则返回empty的Optional对象
     */
    @Test
    public void filterDemo() {
        Optional<String> optional = Optional.of("ABC").filter(value -> value.contains("A"));
        System.out.println(optional);//=>Optional[ABC]

        optional = Optional.of("ABC").filter(value -> value.contains("a"));
        System.out.println(optional);//=>Optional.empty
    }

    /**
     * map(Function mapper):如果isPresent()==true,则调用Function实例的apply(value)对value进行相关逻辑操作,然后返回一个新的Optional对象,否则返回一个empty的Optional对象
     * 相当于:
     * if(value!=null){
     *      //对value进行逻辑操作
     *      //产生了一个newValue
     *      //return new Optional,返回一个value类型为NewValue的Optional对象
     * }else{
     *      //return Optional.empty(),返回一个空的Optional对象
     * }
     */
    @Test
    public void mapDemo() {
        Optional<UserInfo> userInfoOptional = Optional.of("zhangxy~25").map(value -> {
            String[] array = value.split("~");
            return new UserInfo(array[0], Integer.parseInt(array[1]));
        });

        System.out.println(userInfoOptional);
    }

    /**
     * flatMap(Function mapper):和map(Function mapper)作用相同
     * 不同的是Function实例的apply()方法如果返回null,将会抛出NullPointerExecption
     * 不同的是Function实例的apply()方法如需要显示的返回一个Optional对象
     */
    @Test
    public void flatMapDemo() {
        Optional<UserInfo> userInfoOptional = Optional.of("zhangxy~25").flatMap(value -> {
            String[] array = value.split("~");
            //return Optional.of(new UserInfo(array[0], Integer.parseInt(array[1])));
            return null;
        });

        System.out.println(userInfoOptional);
    }

    /**
     * orElse(T t):Optional实例的value==null,则返回t(即传入的值),否则返回Optional实例的value
     * 相当于:
     * if(value==null){
     *      return t;
     * }else{
     *      reutrn value;
     * }
     */
    @Test
    public void orElseDemo() {
        Optional<String> optional = Optional.of("小明");
        System.out.println(optional.orElse("小李"));

        optional = Optional.empty();
        System.out.println(optional.orElse("小李"));
    }

    /**
     * orElseGet(Supplier other):作用和orElse(T t)类似
     * Optional实例的value==null,则返回Supplier实例的get()方法返回值,否则返回Optional实例的value
     * 相当于:
     * if(value==null){
     *      return get();
     * }else{
     *      reutrn value;
     * }
     */
    @Test
    public void orElseGetDemo() {
        Optional<String> optional = Optional.of("小明");
        System.out.println(optional.orElse("小李"));

        optional = Optional.empty();
        System.out.println(optional.orElseGet(() -> {
            return "小李";
        }));
    }

    /**
     * orElseThrow():作用和orElse(T t)类似
     * Optional实例的value==null,则爬出Supplier实例的get()方法返回的异常,否则返回Optional实例的value
     * 相当于:
     * if(value==null){
     *     throw get();
     * }else{
     *     return value;
     * }
     * @throws Exception
     */
    @Test
    public void orElseThrowDeom() throws Exception {
        Optional<String> optional = Optional.of("小明");
        optional.orElseThrow(() -> {
            return new Exception("测试异常");
        });

        optional = optional = Optional.empty();
        optional.orElseThrow(() -> {
            return new Exception("测试异常");
        });
    }

    /**
     * 返回名字列表
     *
     * @return
     */
    @Test
    public List<String> getListName() {
        /*Java8之前的写法*/
        /*
        List list = null;
        if (list == null) {
            return Collections.emptyList();
        } else {
            return list;
        }
        */

        /*Java8 Optional写法*/
        List<String> list = null;
        return Optional.of(list).orElse(Collections.emptyList());
    }

    /**
     * 打印名字到控制台
     */
    @Test
    public void printName(){
        String name = "Tom";
        /*Java8之前的写法*/
        if (name != null) {
            System.out.println(String.format("name:%s",name));
        }

        /*Java8 Optional写法*/
        Optional.ofNullable(name).ifPresent(value -> System.out.println(String.format("name:%s",value)));
    }

    /**
     * 名字首字母大写
     */
    @Test
    public void nameFormatDemo() {
        final String DEFAULT_NAME = "no name";
        /*Java8之前的写法*/
        String name = "tom";
        if (name != null) {
            name = name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
        }else{
            name = DEFAULT_NAME;
        }
        System.out.println(String.format("Java8之前的写法,name:%s", name));

        /*Java8 Optional写法*/
        name = "tom";
        //name = null;
        Optional<String> nameOptional = Optional.ofNullable(name);
        name =  nameOptional.map(value -> value.substring(0, 1).toUpperCase() + value.substring(1, value.length())).orElse(DEFAULT_NAME);

        System.out.println(String.format("Java8 Optional写法,name:%s", name));
    }
}

class UserInfo implements Serializable {
    private String name;
    private Integer age;

    public UserInfo(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("name", name)
                .append("age", age)
                .toString();
    }
}

参考资料:https://yanbin.blog/proper-ways-of-using-java8-optional/
https://yanbin.blog/java8-optional-several-common-incorrect-usages/

你可能感兴趣的:(Java8)