java代码之美(16) —Java8 Optional
总结JavaScript对象的深浅拷贝
Java8 Optional
一句话引见Optional类:运用JDK8的Optional类来防备NullPointerException(空指针异常)问题
。
一、媒介
在我们开放过程当中,遇到的异常中NullPointerException必定是排行第一的。所以在日常平凡编码中,我们会常常的推断null。
public void saveCity(City city) {
if (city != null) {
String cityName = city.getCityName();
if (cityName != null) {
String code = cityDao.findCodeByName(cityName);
city.setCode(code);
cityDao.save(city);
}
}
}
虽然上面代码变得越发平安,然则过量嵌套 if 语句下降代码团体可读性,进步复杂度。我们能够优化下代码
public void saveCity(City city) {
if (city == null) {
return;
}
String cityName = city.getCityName();
if (cityName == null) {
return;
}
String code = cityDao.findCodeByName(cityName);
city.setCode(code);
cityDao.save(city);
}
如许还能够,但我们经由过程Optional变的更简约
public void saveCity(City city) {
//就一行 city不为空返回 都市称号 不然直接返回空
Optional<String> roleOpt = Optional.ofNullable(city).map(City::getCityName);
//假如容器中 不为空
if (roleOpt.isPresent()) {
String code = cityDao.findCodeByName(roleOpt.get());
city.setCode(code);
cityDao.save(city);
}
}
如许,我们仅需要对我们体贴的做一次校验,省却了前面的一系列的磨练操纵。
二、Optional API
观点
Optiona实质是一个容器,容器中存在为null或许不包括非null值的容器对象。供应了一系列的要领供我们推断该容器里的对象是不是存在。
1、JDK源码
/**
* final润饰代表不能被子类继续
*/
public final class Optional<T> {
/**
* 建立一个空容器
*/
private static final java.util.Optional<?> EMPTY = new java.util.Optional<>();
/**
* 传入的值
*/
private final T value;
/**
* 组织函数私有化 申明不能被外部new
*/
private Optional() {
this.value = null;
}
/**
* 私有化组织函数
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
/**
* 猎取空容器
*/
public static <T> java.util.Optional<T> empty() {
@SuppressWarnings("unchecked")
java.util.Optional<T> t = (java.util.Optional<T>) EMPTY;
return t;
}
/**
* 传入的对象不能为空 不然抛异常
*/
public static <T> java.util.Optional<T> of(T value) {
return new java.util.Optional<>(value);
}
/**
* 传入的对象能够为空
*/
public static <T> java.util.Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/**
* 猎取容器对象的要领 注重 假如用这个要领则代表容器中肯定有对象,不然抛异常
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* 推断容器对象是不是为空
*/
public boolean isPresent() {
return value != null;
}
/**
* 假如容器对象为空 则返回当前对象
*/
public T orElse(T other) {
return value != null ? value : other;
}
//==========有关下面这几个JDK8自带的函数式接口的作用,上一篇博客有细致申明,这里就不多说了。
/**
* 传入Consumer编程式接口参数
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
/**
* 传入Predicate编程式接口参数
*/
public java.util.Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
/**
* 传入Function编程式接口参数
*/
public <U> java.util.Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return java.util.Optional.ofNullable(mapper.apply(value));
}
}
/**
* 传入Function编程式接口参数
*/
public <U> java.util.Optional<U> flatMap(Function<? super T, java.util.Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
/**
* 传入Supplier编程式接口参数
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
/**
* 传入Supplier编程式接口参数
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
}
2、建立Optional对象
经由过程上面源码能够看出,Optional的组织函数都是私有化的,没法直接new对象。它这边供应了3个静态要领猎取对象。
1、建立一个肯定是空的Optional容器
Optional<Car> optCar = Optional.empty();
2、建立一个肯定黑白空值Optional容器
(传入的对象不能够为null,不然抛出NullPointerException)
Optional<Car> optUser = Optional.of(user);
3、建立一个多是空也大概不为空的Optional容器
(传入的对象能够为null)
Optional<Car> optUser = Optional.ofNullable(user);
3、总结经常使用要领
1、isPresent() //有值则返回true
2、get(): //值存在时返回值,不然抛出一个NoSuchElement异常(所以调这个,平常先推断上面要领返回是不是为true)
3、orElse(T other) //值存在时返回值,不然返回一个默认值
4、ifPresent(Consumer<T> block) //会在值存在的时刻实行给定的代码块
5、orElseThrow(Supplier<? extends X> exceptionSupplier) //与get()类似,差别的是能够自定义异常范例
6、orElseGet(Supplier<? extends T> other) //orElse要领的耽误挪用版,Supplier要领只要在Optional对象不含值时才实行挪用
7、map/flatMap/filter //与Stream中用法类似
三、完全的示例
这里写一个针对以上API都涉及到的Demo,这个例子邃晓了,那末Optional的运用也就都清晰了。
代码
public class OptionalDemo {
public static void main(String[] args) {
//1、建立Optional实例,传入的对象不能为null
Optional<String> nameOptional = Optional.of("张三");
//2、建立Optional实例,传入对象能够为null,也能够不weinull
Optional emptyOptional = Optional.ofNullable(null);
//3、isPresent要领用来搜检Optional实例是不是有值。
if (nameOptional.isPresent()) {
//挪用get()返回Optional值。
System.out.println("1、" + nameOptional.get());
}
try {
//4、在Optional实例上挪用get()抛出NoSuchElementException。
System.out.println("2、" + emptyOptional.get());
} catch (NoSuchElementException ex) {
System.out.println("3、异常" + ex.getMessage());
}
//
//5、假如Optional值不为空,lambda表达式会处置惩罚并在其上实行操纵。(这里x代表就是nameOptional中的对象)
nameOptional.ifPresent((x) -> {
System.out.println("4、字符串长度为: " + x.length());
});
//6、假如有值orElse要领会返回Optional实例,没值则返回当前值
System.out.println("5、"+ emptyOptional.orElse("假如是空容器则返回李四"));
System.out.println("6、"+nameOptional.orElse("假如是空容器则返回王五"));
//7、orElseGet与orElse类似,区分在于传入的参数差别,一个是直接传入对象,这个是传入Supplier函数式接口
System.out.println("7、" + emptyOptional.orElseGet(() -> "李四"));
System.out.println("8、" + nameOptional.orElseGet(() -> "王五"));
try {
//8、假如是空容器,则能够抛出自定义异常。
emptyOptional.orElseThrow(() -> new NullPointerException("空容器异常"));
} catch (Throwable ex) {
System.out.println("9、" + ex.getMessage());
}
Optional<String> ageOptional = Optional.of("10");
//9、这里入参是Function,所以能够转换容器中的对象 比如将String对象转为Integer对象
Optional<Integer> age = ageOptional.map((value) -> Integer.parseInt(value));
/**
* 10、flatMap与map(Funtion)异常类似,差别在于 map返回能够将String对象转为Integer对象,但flatMap转换后肯定照样String对象
*/
Optional<String> upperName = nameOptional.flatMap((value) -> Optional.of(value.toUpperCase()));
//11、filter要领搜检Optiona值是不是满足给定前提。假如满足返回Optional实例值,不然返回空Optional。
Optional<String> longName = nameOptional.filter((value) -> value.length() > 6);
System.out.println("10、" + longName.orElse("longName容器的名字长度小于6位"));
//12、另一个示例,Optional满足给定前提。
Optional<String> anotherName = Optional.of("乌啦啦市长公主");
Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
System.out.println("11、" + shortName.orElse("anotherName容器的名字长度小于6位"));
}
}
运转效果
参考
1、JDK8新特征之:Optional
2、Optional类包括的要领引见及其示例
你假如情愿有所作为,就必须善始善终。(26)
Java基础——多线程