JDK8新特性之Optional操作

JDK8新特性之Optional操作

  • 1 Optional 类简介
  • 2 Optional 的基本操作
  • 3 Optional 使代码更简洁
  • 5 Optional 在实际开发中的应用
    • 5.1 案列
    • 5.2 使用Optional解决繁琐的非空判断

1 Optional 类简介

  JDK8 中引入的 Optional 类可以解决空指针异常, 让我们省略繁琐 的非空判断. Optional 类就是一个可以为 null 容器, 或者保存指定类型的数据, 或者为 null.

package java.util;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public final class Optional<T> {
    /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * If non-null, the value; if null, indicates no value is present
     */
    private final T value;

    /**
     * value为空的Optional类型对象
     */
    private Optional() {
        this.value = null;
    }

    /**
     * 返回一个空的Optional对象
     */
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * 如果为空,抛出一个空指针异常
     */
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 封装为一个Optional 类型的对象
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    /**
     * 把指定的 value 值封装为 Optional 对象,如果 
     * value 为 null 返回一个空的 Optional 对象
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 如果值存在返回, 如果不存在抛出异常 NoSuchElementException
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 判断值是否存在
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * 如果值存在就执 行 consumer 函数,否则什么也不做
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    /**
     * 如果有值,返回符合 predicate 条件的 Optional 对象, 否则返回空的 Optional 对象
     */
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

    /**
     * 如果值存在 就执行 mapper 映射函数,
     */
    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));
        }
    }

    /**
     * 如果 有值,执行 mapper 映射函数,返回 Optional 对象, 如果没有值返 回空的 Optional 对象
     */
    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));
        }
    }

    /**
     * 如果值存在就返回,如果不存在返回 other
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * 如果存在就返回值, 如果不存在,执行 Supplier 返回另外一个值
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 如果存在就返回该值,如果不存在抛出由 exceptionSupplier 生成的异常
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

    /**
     * 重写equals方法
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Optional)) {
            return false;
        }

        Optional<?> other = (Optional<?>) obj;
        return Objects.equals(value, other.value);
    }

    /**
     * Objects类的hashcode方法
     */
    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    /**
     * 重写toString 方法
     */
    @Override
    public String toString() {
        return value != null
            ? String.format("Optional[%s]", value)
            : "Optional.empty";
    }
}

2 Optional 的基本操作

public class Test01 {
    public static void main(String[] args) {

        //1 把一个字符串封装为Optional对象
        //参数不能为null,否则抛出NullPointException
        Optional<String> ofString = Optional.of("hello");

        //Optional ofString1 = Optional.of(null);

        //2 为指定的值创建Optional对象(可以为空)
        Optional<String> ofString2 = Optional.ofNullable(null);
        System.out.println(ofString2);//Optional.empty

        //3 直接创建一个空的Optional对象
        Optional<Object> empty = Optional.empty();
        System.out.println(empty);//Optional.empty

        //4 获得 Optional 对象中的值,如果值不存在会产生异常
        String text = ofString.get();
        System.out.println(text);
        String text2 = ofString2.get(); //java.util.NoSuchElementException

        //5 如果 Optional 对象中有值就返回,没有则返回指定的其他值
        text = ofString.orElse("another");

        //6 如果有值就返回,如果 Optional 对象中没值则创建一个新的
        text = ofString2.orElseGet(() -> "newString");
        System.out.println( text ); //newString

        //7 orElseThrow(),如果值存在就返回,否则抛出异常 /
        text = ofString2.orElseThrow(NullPointerException::new);
        text = ofString.orElseThrow(NullPointerException::new);
        System.out.println( text );


        //8 filter(),如果 Optional 对象有值返回满足指定条件的 Optional 对象
        // , 否则返回空 的 Optional 对象
        text = ofString.filter(s -> s.length() > 10).orElse("lenth is letter than 10");
        System.out.println( text );
        text = ofString.filter(s -> s.length() > 3).orElse("lenth is letter than 3");
        System.out.println( text );


        //9 如果 Optional 对象的值存在,执行 mapper 映射函数
        text = ofString.map(x -> x.toUpperCase()).orElse("Failure");
        System.out.println( text );
        text = ofString2.map(x -> x.toUpperCase()).orElse("Failure");
        System.out.println( text ); //Failure
        
        //10 ifPresent() 如果 Optional 对象有值就执行 Consumer 函数 
        ofString.ifPresent(s -> System.out.println("处理数据" + s)); 
        ofString2.ifPresent(s -> System.out.println("处理数据" + s)); //没有值什么也 不做 System.out.println("optional");


    }
}

3 Optional 使代码更简洁

public class Test02 {
    public static void main(String[] args) {
        Address address = new Address("Beijing", "TianAnMen");
        User user = new User("zhangsan", address);
        User user1 = new User();
        User user2 = null;
        System.out.println(getName1(user));
        System.out.println(getName2(user1));
        System.out.println(getCity1(user2));
        System.out.println(getCity2(user));
    }

    /**传统写法**/
    //定义方法返回指定用户的用户名 ,如果用户名不存在返回unknown
    public static String getName1(User user) {
        if (user == null) { //判断参数接收的 User 对象是否为 null
            return "unknown";
        }
        return user.name;
    }

    //Optional 可以解决空指针问题
    public static String getName2(User user) {
        return Optional.ofNullable(user)     //把参数接收的 user 对象包装为 Optional 对象
                .map(u -> u.name)            //映射,只需要用户名
                .orElse("unknown");    //存在就返回,不存在返回 unknown
    }

    /**传统写法**/
    //定义方法返回指定用户的城市
    public static String getCity1(User user) {
        if (user != null) {
            if (user.address != null) {
                return user.address.city;
            }
        }
        return "unkown";
    }

    //使用 Optional 返回用户的城市
    public static String getCity2(User user) {
        return Optional.ofNullable(user)    //把参数对象包装为 Optional 对象
                .map(u -> u.address)        //映射用户的地址
                .map(addr -> addr.city)     //映射地址的城市
                .orElse("Unkown");    //有就返回,没有返回 Unknown
    }
}

//定义用户类
class User {
    String name;
    Address address;

    public User(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public User() {
    }
}

class Address {
    String city;
    String house;

    public Address(String city, String house) {
        this.city = city;
        this.house = house;
    }
}

5 Optional 在实际开发中的应用

5.1 案列

   如果每一个人都有一辆车,没辆车都有一个保险,每个保险都有一个名字,那么保险类、车类、人类就可以这样定义。

/**
 * 保险类
 */
public class Insurance {
    private  String name;

    public String getName() {
        return name;
    }
}

/**
 * 汽车类
 */
public class Car {

	//汽车有保险
    private  Insurance insurance;      

    public Insurance getInsurance() {
        return insurance;
    }
}

/**
 * 人类
 */
public class Person {
 	//人有小汽车
    private Car car;       

    public Car getCar() {
        return car;
    }

    public Person setCar(Car car) {
        this.car = car;
        return this;
    }
}

   测试类:获取某一个人的小汽车的保险的名称

/**
 * 每个人有一部车,每辆车都有保险,每个保险公司都有自己的名称
 */
public class Test {
    public static void main(String[] args) {
    
        Person  lisi = new Person();
        //lisi的car属性默认初始化为null
//        getCarInsuranceName(lisi);  //产生了空指针异常

        Car benz = new Car();   //insurance默认初始化为null
        lisi.setCar(benz);
        getCarInsuranceName(lisi);
    }
    //获得某个人的汽车的保险的名称
    public static  String getCarInsuranceName3( Person person){
    
        if ( person == null ){          //人不存在
            return "Unknown";
        }
        Car car = person.getCar();
        if (car == null){               //车不存在
            return "Unknown";
        }
        Insurance insurance = car.getInsurance();;
        if ( insurance == null){        //没有保险
            return "Unknown";
        }

        return person.getCar().getInsurance().getName();
    }
    //获得某个人的汽车的保险的名称
    public static  String getCarInsuranceName2( Person person){
    
        if ( person != null ){          //人存在
            Car car = person.getCar();
            if ( car != null ){         //人有车
                Insurance insurance = car.getInsurance();
                if ( insurance != null){        //车有保险
                    return  insurance.getName();
                }
            }
        }
        return "Unknown";
    }

    //获得某个 人的汽车的保险的名称
    public static  String getCarInsuranceName( Person person){
    
        return person.getCar().getInsurance().getName();
    }
    /*
        这段代码存在问题:
            并不是所有的人都有车, 如果没有车的话,getCar()会返回null,运行时会产生空指针异常
            并不是所有的车都有保险,如果没有保险,getInsurance()返回null
     */
}

5.2 使用Optional解决繁琐的非空判断

  重新定义保险类、汽车类、人类

/**
 * 保险类
 */
public class Insurance {

    private  String name;

    public String getName() {
        return name;
    }

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

/**
 * 汽车类
 */
public class Car {

	//汽车品牌
    private String brand;       

	//不能确定每辆汽车都有保险
    private Optional<Insurance>  insurance;         

    public Car(String brand, Optional<Insurance> insurance) {
        this.brand = brand;
        this.insurance = insurance;
    }

    public String getBrand() {
        return brand;
    }

    public Car setBrand(String brand) {
        this.brand = brand;
        return this;
    }

    public Optional<Insurance> getInsurance() {
        return insurance;
    }

    public Car setInsurance(Optional<Insurance> insurance) {
        this.insurance = insurance;
        return this;
    }
}


/**
 * 定义人类
 */
public class Person {

    private String name;

	//不确定是否有车
    private Optional<Car> car;      

    public Person(String name, Optional<Car> car) {
        this.name = name;
        this.car = car;
    }

    public String getName() {
        return name;
    }

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

    public Optional<Car> getCar() {
        return car;
    }

    public Person setCar(Optional<Car> car) {
        this.car = car;
        return this;
    }
}

  测试类

/**
 * 每个人可能有一部车,每辆车可能都有保险,每个保险公司都有自己的名称
 */
public class Test {
    public static void main(String[] args) {
        //1)创建保险对象
        Insurance in1 = new Insurance();
        in1.setName("pingan");
        Optional<Insurance> insurance1 = Optional.ofNullable(in1);  //有保险
        Optional<Insurance> insurance2 = Optional.ofNullable(null);   //保险为null

        //2)创建小汽车对象
        Car car1 = new Car("Geely", insurance1);        //Geely汽车有保险
        Car car2 = new Car("Haval", insurance2);        //Haval汽车没有保险
        Optional<Car> carOptional1 = Optional.ofNullable(car1);     //车有保险
        Optional<Car> carOptional2 = Optional.ofNullable(car2);     //车无保险
        Optional<Car> carOptional3 = Optional.ofNullable(null) ;    //没有车

        //3)创建Person对象
        Person p1 = new Person("lisi", carOptional1);       //lisi有车,有保险
        Person p2 = new Person("wangwu", carOptional2);     //wangwu,有车,没有保险
        Person p3 = new Person("zhaoliu", carOptional3);    //zhaoliu, 没有车

        //4)使用Optional包装Person对象
        Optional<Person> person1 = Optional.ofNullable(p1);     //有车,有保险
        Optional<Person> person2 = Optional.ofNullable(p2);     //有车,没有保险
        Optional<Person> person3 = Optional.ofNullable(p3);     //没有车

        //5)获得人的汽车品牌
        System.out.println( person1.map(Person::getCar));   
        //返回一个Optional>类型的数据
        System.out.println( person1.flatMap(Person::getCar));  
        //Optional
        
        System.out.println( person1.flatMap(Person::getCar).map(Car::getBrand).orElse("Unknown"));
        System.out.println( person2.flatMap(Person::getCar).map(Car::getBrand).orElse("Unknown"));
        System.out.println( person3.flatMap(Person::getCar).map(Car::getBrand).orElse("Unknown"));

        //6)获得人的汽车的保险的名称
        System.out.println( person1.flatMap(Person::getCar)
                    .flatMap(Car::getInsurance)
                    .map(Insurance::getName)
                    .orElse("Unknwon"));
        System.out.println( person2.flatMap(Person::getCar)
                    .flatMap(Car::getInsurance)
                    .map(Insurance::getName)
                    .orElse("Unknwon"));
        System.out.println( person3.flatMap(Person::getCar)
                    .flatMap(Car::getInsurance)
                    .map(Insurance::getName)
                    .orElse("Unknwon"));

    }
}

  

注意:
1 .map() 和 flatMap() 方法的使用。map() 方法的返回值,又对结果进行了一次包装。具体可以看Optional类的源码
2. 明显可以看出使用Optional类型,作为成员变量的属性,可以减少很多非空判断,代码可读性更高。
3 在实际开发中应当多应用。

你可能感兴趣的:(JDK8)