本文共 4478 字,大约阅读时间需要 14 分钟。
引入一个新的类java.util.Optional<T>,这个类封装了Optional的值。
问题:什么时候要用Optional包裹字段,什么不应该用?
(1)应该用Optional的情况:当你认为这个字段可能为null,也可能部位null,或者你自己也不确定的情况。比如:一个人可能有车,也可能没有车,此时,你就应该用一个Optional类来包装,当值为null时对应的就是一个空的Optional对象。
(2)无需Optional的情况:就是你已经明确的知道,某个字段一定不为null,则无需用Optional。
代码如下:
class Person{ private Car car; public OptionalgetCar(){ return Optional.ofNullable(car); } public void setCar(Car car) { this.car = car; }}class Car{ private Insurance insurance; public Optional getInsurance(){ return Optional.ofNullable(insurance); } public void setInsurance(Insurance insurance) { this.insurance = insurance; }}class Insurance{ private String name; public String getName(){ return name; }}public class NullException { public static String getCarInsuranceName(Optional person){ return person.flatMap(p->p.getCar()) .flatMap(car->car.getInsurance()) .map(insurance->insurance.getName()) //到这里还是一个Optiona
输出:
Unkonwn
注意:上述未对字段进行Optional封装,是为了实现序列化,而只是在get相应字段中加入了Optional.
补充:关于Optional实例中的变量值(1)get方法:(不推荐)如果变量存在(不为null),则直接返回封装的变量值,否则抛出一个NoSuchElementException异常。
(2)orElse(T other):(推荐)其中类型T和Optional<T>中的T是一样的。如果变量存在(不为null),则返回类型为T的变量的值,否则返回T oher。由表达式可知,other是个变量因此,需要预先计算出来。
(3)orElseGet(Supplier<? extends T> other):(推荐)是orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时(即为null)才执行调用。(这是因为这里传入的是一个行为参数,即lambda表达式)。适用场景是:如果产生默认值耗时比较长可以调用此方法。
(4)orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常类似。当Optional对象为空(即为null)时都会抛出一个异常,且这个异常可以是你自己定制的。
(5)ifPresent(Consumer<? super T>)让你能在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。该方法返回是void,参数是类似行为参数,也是传入一个lambda表达式。举几个栗子:
public class TestOptional { class Person{ private String name; //绝对不可能为null private String address; //有可能为null private String sex; //绝对不可能为null public String getName(){ return name; } public void setName(String name){ this.name = name; } public OptionalgetAddress(){ return Optional.ofNullable(this.address); } public void setAddress(String address){ this.address = address; } public String getSex(){ return sex; } public void setSex(String sex){ this.sex = sex; } } public static void main(String[] args) { //初始化值 TestOptional testOptional = new TestOptional(); TestOptional.Person person = testOptional.new Person(); //这里的new Eclipse不会显示提示,内部类,外部调用比较麻烦点,内部调用还是比较方便 person.setSex("boy"); person.setName("tim"); Optional address = person.getAddress();// address.get(); String add = address.orElse("default address"); String add2 = address.orElseGet(()->{ return "default address"; }); String add3 = address.orElseThrow(()->{ return new Exception(); }); address.ifPresent((t)->{;}); //这一步只能对对象进行更改,如果是:String或者包装类型以及基本数据类型不起作用 }}
filter代替if语句
public static voidmain(String[] args) {
//传统的写法
Room room1 = newRoom("timchen", "525");
if(room1.getName().equals("timchen")){
System.out.println("equal" + room1.getName());
}
//java 8 写法
Optional<Room> room =Optional.ofNullable(new Room("timchen", "525"));
room.filter((test)-> "timchen".equals(test.getName())).ifPresent(x->System.out.println("equal" + x.getName()));
}
可以看到,java8尽量能够少用if语句。如果想对if/else进行改进,在项目中看到很多人可能这么写:
//传统的写法 Room room1 = new Room("timchen", "525"); if(room1.getName().equals("timchen525")){ System.out.println("equal " + room1.getName()); }else{ System.out.println("not equal " + room1.getName()); } //java 8 写法 Optionalroom = Optional.ofNullable(new Room("timchen", "525")); Optional room2 = room.filter((r)->"timchen525".equals(r.getName())); if(room2.isPresent()){ System.out.println("equal " + room1.getName()); }else{ System.out.println("not equal"); }
可以看到,如果用到if/else语句,可能传统的写法代码更少。