Optional源码解析与实践

2023-05-28 0 326

1 编者按

NullPointerException在合作开发操作过程中时常碰到,处理不当小BUG就再次出现了,假如防止那个难题呢,Optional是专门针对化解那个难题的类,所以Optional怎样采用呢?让他们一同积极探索呵呵吧!

2 源代码导出

2.1 Optional表述

Optional类是Java8为的是化解null值推论难题而建立的罐子类,在java.util 下,采用Optional类能防止隐式的null值推论,防止null引致的NullPointerException。具体来说,Optional是三个罐子,它能留存类别T的值,也能为null的罐子第一类。Optional罐子根本无法存三个值。

2.2 Optional的特性

1)源代码:

/** * 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;

依照源代码能看见Optional有三个特性,三个是为常量预备的EMPTY和C#值value;

2.3 Optional的方式

Optional除toString()、hashCode() 、equals()等Object的方式外,还包涵下列方式。

2.3.1 专有构造方式

/** * Constructs an empty instance. * * @implNote Generally only one empty instance, {@link Optional#EMPTY}, * should exist per VM. */ private Optional() { this.value = null; } /** * Constructs an instance with the value present. * * @param value the non-null value to be present * @throws NullPointerException if value is null */ private Optional(T value) { this.value = Objects.requireNonNull(value); }

分别是建立三个空实例和构造三个具有当前值的实例。

2.3.2 建立方式

1)源代码

public static<T> Optional<T>empty() { @SuppressWarnings(“unchecked”) Optional<T> t = (Optional<T>) EMPTY; returnt; }public static <T> Optional<T> of(T value) { return new Optional<>(value); } public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }

2)方式说明

empty(): 建立三个空的 Optional 实例of(T t) : 建立三个 Optional 实例,当 t为null时抛出异常ofNullable(T t): 建立三个 Optional 实例,但当 t为null时不会抛出异常,而是返回三个空的实例

3)测试代码

public static void main(String[] args) { Integer value1 = null; Integer value2 = 1; try{ Optional<Integer> optional1 = Optional.empty(); System.out.println(“optional1建立了”); }catch(Exception e){ System.out.println(“optional1失败了”); } try{ Optional<Integer> optional2 = Optional.of(value1); System.out.println(“optional2建立了”); }catch (Exception e){ System.out.println(“optional2失败了”); } try{ Optional<Integer> optional3 = Optional.ofNullable(value1); System.out.println(“optional3建立了”); }catch (Exception e){ System.out.println(“optional3失败了”); }try { Optional<Integer> optional4 = Optional.of(value2); System.out.println(“optional4建立了”); }catch (Exception e){ System.out.println(“optional4失败了”); } try{ Optional<Integer> optional5 = Optional.ofNullable(value2); System.out.println(“optional5建立了”); }catch(Exception e){ System.out.println(“optional5失败了”); } }

4)运行结果

Optional源码解析与实践

1)源代码

public T get() { if (value==null) { throw new NoSuchElementException(“No value present”); } return value; }

2)方式说明

get(): 假如Optional不为空,则返回该Optional罐子中的值,否则抛出NoSuchElementExceptio 。

3)测试代码

public static void main(String[] args){ Integer value1 =null; Integer value2 = 1; Optional<Integer> optional1 = Optional.ofNullable(value1); Optional<Integer> optional2 = Optional.of(value2);try { Integer result=optional1.get(); System.out.println(“optional1的值是:”+result); }catch (Exception e){ System.out.println(+e.getMessage()); } try { Integer result=optional2.get(); System.out.println(“optional2的值是:”+result); }catch (Exception e){ System.out.println(因:”+e.getMessage()); } }

4)运行结果

Optional源码解析与实践

2.3.4 推论方式

1)源代码

public boolean isPresent() { return value != null; }public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }public T orElse(T other) { return value != null ? value : other; } public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throwexceptionSupplier.get(); } }

2)方式说明

isPresent(): 推论optional是否为空,假如空则返回false,否则返回trueifPresent(Consumer c): 假如optional不为空,则将optional中的第一类传给Comsumer函数orElse(T other): 假如optional不为空,则返回optional中的第一类;假如为null,则返回 other 那个第一类。orElseGet(Supplier other): 假如optional不为空,则返回optional中的第一类;假如为null,否则调用其他函数并返回调用的结果orElseThrow(Supplier exception): 假如optional不为空,则返回optional中的第一类;假如为null,则抛出Supplier函数生成的异常

3)测试代码

public static void main(String[] args) { Integer value1 = null; Integer value2 = 1; Optional<Integer> optional1 = Optional.ofNullable(value1); Optional<Integer> optional2 = Optional.of(value2);try { if(optional1.isPresent()){ System.out.println(“optional1的isPresent结果不为空”); }else{ System.out.println(“optional1的isPresent结果为空”); } }catch (Exception e){ System.out.println(“optional1的isPresent判空失败,原因:”+e.getMessage()); } try { if(optional2.isPresent()){ System.out.println(“optional2的isPresent结果不为空”); }else{ System.out.println(“optional2的isPresent结果为空”); } }catch(Exception e){ System.out.println(“optional2的isPresent判空失败,原因:”+e.getMessage()); } optional1.ifPresent(t->{int i =t+1; System.out.println(“optional1处理后的值是”+i); }); optional2.ifPresent(t->{int i =t+1; System.out.println(“optional2处理后的值是”+i);}); Integer value3 = 2; Integer result = optional1.orElse(value3); System.out.println(“optional1执行orElse处理后的值是”+result); result = optional2.orElse(value3); System.out.println(“optional2执行orElse处理后的值是”+result); result = optional1.orElseGet(()->new Integer(-1)); System.out.println(“optional1执行orElseGet处理后的值是”+result); result = optional2.orElseGet(()-> new Integer(-1)); System.out.println(“optional2执行orElseGet处理后的值是”+result); try { result = optional1.orElseThrow (()-> new RuntimeException(“值是空的”)); System.out.println(“optional1执行orElseThrow处理后的值是”+result); }catch(Exception e){ System.out.println(“optional1的orElseThrow抛出异常:”+e.getMessage()); } try{ result = optional2.orElseThrow (()->new RuntimeException(“值是空的”)); System.out.println(“optional2执行orElseThrow处理后的值是”+result); }catch (Exception e){ System.out.println(“optional2的orElseThrow抛出异常:”+e.getMessage());

4)运行结果

Optional源码解析与实践

2.3.5 过滤方式

1)源代码

public Optional<T> filter(Predicate<? superT> predicate) { Objects.requireNonNull(predicate);if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }

2)方式说明

filter(Predicate p): 假如optional不为空,则执行Predicate p,假如p的结果为true,则返回原本的optional,否则返回空的optional

3)测试代码

public static void main(String[] args) { Integer value1 = 5; Integer value2 = 6; Optional<Integer> optional1 = Optional.ofNullable(value1); Optional<Integer> optional2 = Optional.of(value2); Optional<Integer> result =optional1.filter(t->t >5); System.out.println(“optional1的filter后的值:”+result); result =optional2.filter(t->t > 5); System.out.println(“optional2的filter后的值:”+result);

4)运行结果

Optional源码解析与实践

2.3.6 映射方式

1)源代码

public<U> Optional<U> map(Function<? superT, ? extends U> mapper) { Objects.requireNonNull(mapper);if (!isPresent()) return empty(); else { returnOptional.ofNullable(mapper.apply(value)); } }public<U> Optional<U> flatMap(Function<? superT, Optional<U>> mapper) { Objects.requireNonNull(mapper);if (!isPresent()) return empty(); else { returnObjects.requireNonNull(mapper.apply(value)); } }

2)方式说明

map(Function mapper): 假如存在三个值,则对其应用提供的映射函数,假如结果非空,则返回描述结果的Optional。 否则返回三个空的Optional。flatMap(Function< T,Optional> mapper): 假如有值,则对其应用提供的可选映射函数,返回结果,否则返回空的可选函数。 那个方式类似于map(Function),但是提供的映射器的结果已经是三个可选的,假如调用,flatMap不会用额外的可选的包装它。区别:map会自动将u放到optional中,而flatMap则需要手动给u建立三个optional

3)测试代码

public static void main(String[] args) { User user1 = null; User user2 = new User(“user2名字”,19); Optional<User> optional1 = Optional.ofNullable(user1); Optional<User> optional2 = Optional.of(user2); System.out.println(“=========map==========”); System.out.println(“optional1的map前的值:”+optional1); Optional<String> result =optional1.map(t->t.getName()); System.out.println(“optional1的map后的值:”+result); System.out.println(“optional2的map前的值:”+optional2); result =optional2.map(t->t.getName()); System.out.println(“optional2的map后的值:”+result); System.out.println(“===========flatMap========”); System.out.println(“optional1的flatMap前的值:”+optional1); Optional<Integer> result2 =optional1.flatMap(t->Optional.ofNullable(t.getAge())); System.out.println(“optional1的flatMap后的值:”+result2); System.out.println(“optional2的flatMap前的值:”+optional2); result2 =optional2.flatMap(t->Optional.ofNullable(t.getAge())); System.out.println(“optional2的flatMap后的值:”+result2); } public class User { String name; Integer age; public User(String name,Integer age){ this.name = name; this.age=age; } public String getName() { returnname; }public Integer getAge() { return age;

4)运行结果

Optional源码解析与实践

3 应用实例

3.1 错误用法

由于Optional并没有实现Serializable接口,所以不能作为类的特性。不要把Optional作为方式的参数。把if(x!=null)直接换成Optional.ofNullable(x).isPresent(),这样有过度编码的嫌疑。直接采用Optional.get()的返回值进行操作,String result =Optional.ofNullable(null).get().toString();这样还是会抛出异常的。

3.2 建议用法

A类有特性B类,B类有特性C类,C类有name那个字段。

采用Optional之前:if(atest!=null){ Btest btest =atest.getBtest(); if(btest!=null){ Ctest ctest = btest.getCtest(); if (ctest != null) { name =ctest.getName(); } } }

采用Optional之后:

name = Optional.ofNullable(atest).map(t->t.getBtest()).map(t->t.getCtest()).map(t->t.getName()).orElse(“默认值”);

代码是不是看上去更整洁了呢?

4 总结

通过对Optional源代码导出和用例测试代码的运行结果,能看出采用Optional能优化null值推论代码,让代码变得更加优雅和整洁。

作者:陈昌浩

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务