为了账号安全,请及时绑定邮箱和手机立即绑定

给女朋友讲解什么是Optional【JDK 8特性】

标签:
Premiere

前言

只有光头才能变强

前两天带女朋友去图书馆了,随手就给她来了一本《与孩子一起学编程》的书,于是今天就给女朋友讲解一下什么是Optional类。

  • 至于她能不能看懂,那肯定是看不懂的。(学到变量/for循环的女人怎么能看懂呢)

不知道大家还记得上一篇《阿里巴巴 Java开发手册》读后感不,当时阅读到空指针异常(NPE)时,书上提到JDK 8有个Optional类供我们使用,该类可以尽可能地防止出现空指针异常(NPE)。

文本力求简单讲清每个知识点,希望大家看完能有所收获

一、基础铺垫

我们都知道JDK 8最重要的新特性是Lambda表达式,这个可以让我们简化非常多的代码编写,不知道大家会使用了没有。这里我简单跟大家来回顾一下~

1.1Lambda简化代码例子

下面就以几个例子来看看Lambda表达式是怎么简化我们代码的编写的。

首先我们来看看创建线程

 public static void main(String[] args) {     // 用匿名内部类的方式来创建线程     new Thread(new Runnable() {         @Override         public void run() {             System.out.println("公众号:Java3y---回复1进群交流");         }     });     // 使用Lambda来创建线程     new Thread(() -> System.out.println("公众号:Java3y---回复1进群交流")); }

再来看看遍历Map集合:

 public static void main(String[] args) {     Map<String, String> hashMap = new HashMap<>();     hashMap.put("公众号", "Java3y");     hashMap.put("交流群", "回复1");     // 使用增强for的方式来遍历hashMap     for (Map.Entry<String, String> entry : hashMap.entrySet()) {         System.out.println(entry.getKey()+":"+entry.getValue());     }     // 使用Lambda表达式的方式来遍历hashMap     hashMap.forEach((s, s2) -> System.out.println(s + ":" + s2)); }

在List中删除某个元素

 public static void main(String[] args) {     List<String> list = new ArrayList<>();     list.add("Java3y");     list.add("3y");     list.add("光头");     list.add("帅哥");          // 传统的方式删除"光头"的元素     ListIterator<String> iterator = list.listIterator();     while (iterator.hasNext()) {         if ("光头".equals(iterator.next())) {             iterator.remove();         }     }     // Lambda方式删除"光头"的元素     list.removeIf(s -> "光头".equals(s));          // 使用Lambda遍历List集合     list.forEach(s -> System.out.println(s)); }

从上面的例子我们可以看出,Lambda表达式的确是可以帮我们简化代码的。

1.1函数式接口

使用Lambda表达式,其实都是建立在函数式接口上的。我们看看上面的代码的接口:

创建多线程的Runnable接口:

 @FunctionalInterface public interface Runnable {     public abstract void run(); }

遍历HashMap的BiConsumer接口:

 @FunctionalInterface public interface BiConsumer<T, U> {     void accept(T t, U u);     default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {         Objects.requireNonNull(after);         return (l, r) -> {             accept(l, r);             after.accept(l, r);         };     } }

在List中删除元素的Predicate接口:

 @FunctionalInterface public interface Predicate<T> {     boolean test(T t);     default Predicate<T> and(Predicate<? super T> other) {         Objects.requireNonNull(other);         return (t) -> test(t) && other.test(t);     }     default Predicate<T> negate() {         return (t) -> !test(t);     }     default Predicate<T> or(Predicate<? super T> other) {         Objects.requireNonNull(other);         return (t) -> test(t) || other.test(t);     }     static <T> Predicate<T> isEqual(Object targetRef) {         return (null == targetRef)                 ? Objects::isNull                 : object -> targetRef.equals(object);     } }

函数式接口的特点:由@FunctionalInterface注解标识,接口有且仅有一个抽象方法!

1.2Lambda简单讲解

或许我们一开始看到Lambda的时候,发现Lambda表达式的语法有点奇葩,甚至有点看不懂。没事,这里3y给大家用图的形式画一画:

webp  Lambda表达式组成

以Runnable接口来举例:

webp  Lambda表达式很简单!

再不济,我们在用IDE的时候,可以提示出Lambda表达式的语法的,这样可以帮我们快速上手Lambda表达式:

webp  IDEA提示Lambda表达式

说白了,我们使用Lambda表达式的架子是这样的()->{},具体的时候看看函数式接口的抽象方法要求就可以了,再不济就使用IDE智能提示。

1.3泛型回顾

比如说public<U> Optional<U> map(Function<? super T, ? extends U> mapper)这个声明,你看懂了吗?

 // 接口 @FunctionalInterface public interface Function<T, R> {     R apply(T t); }

在泛型的上限和下限中有一个原则:PECS(Producer Extends Consumer Super)

  • 带有子类限定的可以从泛型读取【也就是--->(? extend T)】-------->Producer Extends

  • 带有超类限定的可以从泛型写入【也就是--->(? super T)】-------->Consumer Super

解析:传入的参数是泛型 T 或者其父类,返回值是U或其子类。

具体可参考:

二、Optional类

一句话介绍Optional类:使用JDK8的Optional类来防止NPE(空指针异常)问题。

接下来我们看看文档是怎么说的:

A container object which may or may not contain a non-null value.Additional methods that depend on the presence or absence of a contained value are provided

它是一个容器,装载着非NULL元素(或者没有装载元素),提供了一系列的方法供我们判断该容器里的对象是否存在(以及后续的操作)。

Optional类的方法结构图:

webp  Optional类的方法结构图

2.1创建Optional容器

我们先来看看Optional的属性以及创建Optional容器的方法:

     // 1、创建出一个Optional容器,容器里边并没有装载着对象     private static final Optional<?> EMPTY = new Optional<>();     // 2、代表着容器中的对象     private final T value;     // 3、私有构造方法     private Optional() {         this.value = null;     }     // 4、得到一个Optional容器,Optional没有装载着对象     public static<T> Optional<T> empty() {         @SuppressWarnings("unchecked")         Optional<T> t = (Optional<T>) EMPTY;         return t;     }     // 5、私有构造方法(带参数),参数就是具体的要装载的对象,如果传进来的对象为null,抛出异常     private Optional(T value) {         this.value = Objects.requireNonNull(value);     }     // 5.1、如果传进来的对象为null,抛出异常     public static <T> T requireNonNull(T obj) {         if (obj == null)             throw new NullPointerException();         return obj;     }     // 6、创建出Optional容器,并将对象(value)装载到Optional容器中。     // 传入的value如果为null,抛出异常(调用的是Optional(T value)方法)     public static <T> Optional<T> of(T value) {         return new Optional<>(value);     }     // 创建出Optional容器,并将对象(value)装载到Optional容器中。     // 传入的value可以为null,如果为null,返回一个没有装载对象的Optional对象     public static <T> Optional<T> ofNullable(T value) {         return value == null ? empty() : of(value);     }



作者:Java3y
链接:https://www.jianshu.com/p/9143028217b9


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消