这篇文章,介绍Jave8的 Optional 类和接口的 default、static 方法。

1、Optional类

Optional:Java8 java.util包中提供的一个可以包含或者不包含非null值的容器对象。
通过 Optional 我们不用显式进行空值检测 ( if( T == null ) )也很好的解决空指针异常

1.1 Optional API

Optional 方法 说明
static Optional empty() 返回一个空Optional(值为null)
boolean equals(Object obj) 指示给定的对象是否 equals 此Optional的value
Optional filter(Predicate super predicate) 如果 Optional 的值存在而且匹配给定的 predicate(断定型函数式接口),返回当前Optional,否则返回一个空Optional(值为null)
Optional flatMap(Function super T,Optional> mapper) 如果 Optional 的值存在,应用提供的映射方法并返回结果 Optional,否则返回一个空的Optional
T get() 如果此 Optional 存在值,则返回值,否则抛出NoSuchElementException
int hashCode() 返回当前值的哈希码值(如果有),如果没有值,则返回0。
void ifPresent(Consumer super T> consumer) 如果存在值,对该值应用指定的 Consumer(消费型函数式接口),否则不执行任何操作。
boolean isPresent() 如果存在值,返回true,否则返回false
Optional map(Function super T,? extends U> mapper) 如果值存在,对该值应用给定的映射方法,如果是非null的结果,返回一个描述该值的 optional,否则返回一个空Optional(值为null)
static Optional of(T value) 通过给定的value,返回一个值为给定value的Optional实例,value不能为null,若value为null,则抛出NullPointerException
static Optional ofNullable(T value) 通过给定的value,返回一个值为给定value的Optional实例,value可为null
T orElse(T other) 如果此Optional的value不为null,则返回value,否则返回给定的other对象
T orElseGet(Supplier extends T> other) 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier(供给型函数式接口)返回一个T类型的对象
T orElseThrow(Supplier extends X> exceptionSupplier) 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier创建一个Throwable
String toString() 返回非空字符串表示此Optional,适用于调试。

项目中常用的实例方法,用于解决空指针异常

  • isPresent()方法,如果存在值,将返回true,否则返回false。

  • orElse(T other)方法,如果存在值,则返回当前Optional的value,否则返回 other

  • ifPresent(Consumer super T> consumer),如果存在值,对该值应用指定的 Consumer,执行代码块,否则不做任何操作

1.2 Optional 源码

public final class Optional<T> {/**     *  empty()方法的公共实例     */private static final Optional> EMPTY = new Optional<>();

/**     * Optional的值,类型为T     */private final T value;

/**     * 私有构造器     */private Optional() {this.value = null;    }

/**     * 返回一个空Optional(值为null)     */public static Optionalempty() {@SuppressWarnings("unchecked")        Optional t = (Optional) EMPTY;return t;    }/**     * value为入参的构造器,value不能为null,若value为null,则抛出NullPointerException     */private Optional(T value) {this.value = Objects.requireNonNull(value);    }/**     * 通过给定的value,返回一个值为给定value的Optional实例,value不能为null,若value为null,则抛出NullPointerException     */public static  Optionalof(T value) {return new Optional<>(value);    }/**     * 通过给定的value,返回一个值为给定value的Optional实例,value可为null,若value为null,则返回 EMPTY     */public static  OptionalofNullable(T value) {return value == null ? empty() : of(value);    }/**     * 如果此 Optional 存在值,则返回值,否则抛出NoSuchElementException     */public T get() {if (value == null) {throw new NoSuchElementException("No value present");        }return value;    }/**     * 如果存在值 value!=null,返回true,否则返回false     */public boolean isPresent() {return value != null;    }/**     * 如果存在值,对该值应用指定的 Consumer(消费型函数式接口),否则不执行任何操作。     */public void ifPresent(Consumer super T> consumer) {if (value != null)            consumer.accept(value);    }/**     * 如果 Optional 的值存在而且匹配给定的 predicate(断定型函数式接口),返回当前Optional,否则返回一个空Optional(值为null)     */public Optionalfilter(Predicate super T> predicate) {        Objects.requireNonNull(predicate);if (!isPresent())return this;elsereturn predicate.test(value) ? this : empty();    }/**     * 如果值存在,对该值应用给定的映射方法,如果是非null的结果,返回一个描述该值的 optional,否则返回一个空Optional(值为null)     */publicOptional map(Function super T, ? extends U> mapper) {        Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Optional.ofNullable(mapper.apply(value));        }    }/**     * 如果 Optional 的值存在,应用提供的映射方法并返回结果Optional,否则返回一个空的Optional     */publicOptional flatMap(Function super T, Optional> mapper) { Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Objects.requireNonNull(mapper.apply(value)); } }/** * 如果此Optional的value不为null,则返回value,否则返回给定的other对象 */public T orElse(T other) {return value != null ? value : other; }/** * 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier(供给型函数式接口)返回一个T类型的对象 */public T orElseGet(Supplier extends T> other) {return value != null ? value : other.get(); }/** * 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier创建一个Throwable */public T orElseThrow(Supplier extends X> exceptionSupplier) throws X {if (value != null) {return value; } else {throw exceptionSupplier.get(); } }/** * 指示给定的对象是否 equals 此Optional的value */@Overridepublic 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); }/** * 返回当前值的哈希码值(如果有),如果没有值,则返回0。 */@Overridepublic int hashCode() {return Objects.hashCode(value); }/** * 返回非空字符串表示此Optional,适用于调试。 */@Overridepublic String toString() {return value != null ? String.format("Optional[%s]", value) : "Optional.empty"; }}

1.3 Optional 简单使用

public class Person {

//姓名private String name;//年龄private long age;

public Person(String name, long age) {this.name = name;this.age = age;    }

public String getName() {return name;    }

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

public long getAge() {return age;    }

public void setAge(long age) {this.age = age;    }

@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';    }

}

@Testpublic void test() {        Person p = new Person("张三", 18);

// 通过给定的value,返回一个值为给定value的Optional实例,若value为null,则抛出NullPointerException// Optional o = Optional.of(null);        Optional opPerson = Optional.of(p);        System.out.println("of(T value): " + opPerson);// 通过给定的value,返回一个值为给定value的Optional实例,value可为null,若value为null,则返回 Optional.EMPTY        Optional opNull = Optional.ofNullable(null);        System.out.println("ofNullable(T value): " + opNull);// 如果此 Optional 存在值,则返回值,否则抛出NoSuchElementException// Person person = opNull.get();// 抛出NoSuchElementException        Person person = opPerson.get();        System.out.println("T get(): " + person);// 如果存在值 value!=null,返回true,否则返回falseboolean opNullPresent = opNull.isPresent();        System.out.println("opNull persent: " + opNullPresent);if (!opNull.isPresent()) {            System.out.println("opNull 的 value == null");        } else {            System.out.println("opNull 的 value = " + opNull.get());        }boolean opPersonPresent = opPerson.isPresent();        System.out.println("opPerson persent: " + opPersonPresent);// 如果 opPerson 的 value != null,输出下面语句        opPerson.ifPresent(value -> System.out.println(value.getName() + "的年龄是" + value.getAge()));// 如果 Optional 的值存在而且匹配给定的 predicate(断定型函数式接口),返回当前Optional,否则返回一个空Optional(值为null)        System.out.println("opNull.filter(): " + opNull.filter(value -> value.getAge() == 18));        System.out.println("opPerson.filter() 匹配age==18: " + opPerson.filter(value -> value.getAge() == 18));        System.out.println("opPerson.filter() 匹配age==19: " + opPerson.filter(value -> value.getAge() == 19));// 如果值存在,对该值应用给定的映射方法,如果是非null的结果,返回一个描述该值的 optional,否则返回一个空Optional(值为null)// Person::getName 方法引用等同于 lambda表达式:value->value.getName()// Function funcGetName = value->value.getName();        Function funcGetName = Person::getName;        Optional opNameofOpNull = opNull.map(funcGetName);        Optional opNameofOpPerson = opPerson.map(funcGetName);        System.out.println("opNull.map(): " + opNameofOpNull);        System.out.println("opPerson.map(): " + opNameofOpPerson);// 如果 Optional 的值存在,应用提供的映射方法并返回结果 Optional,否则返回一个空的Optional        Optional op1 = opNull.flatMap(value -> Optional.of(new Person("李四", 20)));        Optional op2 = opPerson.flatMap(value -> Optional.of(new Person("李四", 20)));        System.out.println("opNull.flatMap(): " + op1);        System.out.println("opPerson.flatMap(): " + op2);// 如果此Optional的value不为null,则返回value,否则返回给定的other对象        Person wangwu = new Person("王五", 25);        System.out.println("opNull.orElse(): " + opNull.orElse(wangwu));        System.out.println("opPerson.orElse(): " + opPerson.orElse(wangwu));// 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier(供给型函数式接口)返回一个T类型的对象        Supplier supplier = () -> new Person("赵六", 26);        System.out.println("opNull.orElseGet(): " + opNull.orElseGet(supplier));        System.out.println("opPerson.orElseGet(): " + opPerson.orElseGet(supplier));// 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier创建一个Throwable        Supplier nullPointerExceptionSupplier = () -> new NullPointerException("value is null");        System.out.println("opPerson.orElseThrow(): " + opPerson.orElseThrow(nullPointerExceptionSupplier));        System.out.println("opNull.orElseThrow(): " + opNull.orElseThrow(nullPointerExceptionSupplier));    }

运行结果:

of(T value): Optional[Person{name='张三', age=18}]ofNullable(T value): Optional.emptyT get(): Person{name='张三', age=18}opNull persent: falseopNull 的 value == nullopPerson persent: true张三的年龄是18opNull.filter(): Optional.emptyopPerson.filter() 匹配age==18: Optional[Person{name='张三', age=18}]opPerson.filter() 匹配age==19: Optional.emptyopNull.map(): Optional.emptyopPerson.map(): Optional[张三]opNull.flatMap(): Optional.emptyopPerson.flatMap(): Optional[Person{name='李四', age=20}]opNull.orElse(): Person{name='王五', age=25}opPerson.orElse(): Person{name='张三', age=18}opNull.orElseGet(): Person{name='赵六', age=26}opPerson.orElseGet(): Person{name='张三', age=18}opPerson.orElseThrow(): Person{name='张三', age=18}

java.lang.NullPointerException: value is null

  at com.xander.java8._optional.OptionalTest.lambda$test$7(OptionalTest.java:83)    at java.util.Optional.orElseThrow(Optional.java:290)...

2 接口的增强:default 和 static 方法

2.1 default方法

java8中允许接口中包含具有具体实现的方法,用default关键字修饰,这类型方法称为“默认方法”。
不用被default关键字吓到,default 方法也是普通方法,只不过它遵循 "类优先" 原则(下面介绍)

我们看JDK源码时,可以经常看到 default 方法,如 Consumer类:

@FunctionalInterfacepublic interface Consumer<T> {

/**     * Performs this operation on the given argument.     *     * @param t the input argument     */void accept(T t);

/**     * 这就是一个default方法     */default ConsumerandThen(Consumer super T> after) {        Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };    }}

default方法的调用遵循 "类优先" 原则

  • 接口中定义了default方法,如果实现类中重写了该方法,则调用的是实现类中重写后的方法,如果实现类中没有重写default方法,则执行的是接口中定义的default方法。

  • 如果实现类实现了一个接口和继承了一个父类,接口的默认方法和父类中某一个方法具有相同名称和参数列表,而且实现类没有进行该方法的重写,则使用的是父类的方法。

  • 方法冲突,实现类中实现了两个接口,这两个接口中具有相同名称和参数列表的方法(不管是不是default方法),如果实现类中没有对default方法进行重写,则编译出错。实现类中必须必须重写覆盖该方法来解决冲突。

2.2 default方法简单使用

public interface DefaultIntf {

/**     * default 方法     */default void sayHello() {        System.out.println("DefaultIntf say hello 2 you");    }}

public interface SayHelloIntf {/**     * default 方法     */default void sayHello() {        System.out.println("SayHelloIntf hello");    }}

public class Animal {

public void sayHello() {        System.out.println("Animal say hello");    }}

public class Cat implements DefaultIntf {

@Overridepublic void sayHello() {        System.out.println("Hello I am Cat sayHello");    }

}

public class Dog implements DefaultIntf {}

public class Bird extends Animal implements DefaultIntf {}

public class Fish implements SayHelloIntf, DefaultIntf {

/**     * **方法冲突**,类中实现了两个接口,这两个接口中具有相同名称和参数列表的方法(不管是不是default方法),     * 如类中没有对default方法进行重写,则编译出错。子类中必须必须覆盖该方法来解决冲突。     */@Overridepublic void sayHello() {        System.out.println("Hello this is Fish");    }}

@Testpublic void testDefaultMethod() {        DefaultIntf dog = new Dog();        DefaultIntf cat = new Cat();        Bird bird = new Bird();        Fish fish = new Fish();

// 执行默认方法// 实现类中没有重写default方法,执行的是接口中的default        dog.sayHello();// 实现类中对default进行重写,则执行的是重写后的方法        cat.sayHello();// 如果类实现了一个接口和继承了一个父类,接口的默认方法和父类中某一个方法具有相同名称和参数列表,而且子类没有进行该方法的重写,则使用的是父类的方法。        bird.sayHello();// 类中实现了两个接口,这两个接口中具有相同名称和参数列表的方法(不管是不是default方法),子类中必须必须覆盖该方法,否则编译异常。        fish.sayHello();    }

运行结果:

DefaultIntf say hello 2 youHello I am Cat sayHelloAnimal say helloHello this is Fish

2.3 项目实战场景

获取接口实例的泛型Class

/** * Description: 接口:包含一个default方法,该接口所有的实例都可以通过该default获取泛型类型 * * @author Xander * datetime: 2020/9/7 */public interface GenericIntf<T> {

/**     * 默认方法:获取泛型T的 Class     *     * @return     */default ClassgetGenericClass() {        Type[] types = this.getClass().getGenericInterfaces();        ParameterizedType parameterizedType = (ParameterizedType) types[0];        Class tClass = (Class) parameterizedType.getActualTypeArguments()[0];return tClass;    }}/** * Description: GenericIntf的实现类,泛型类型是Double * * @author Xander * datetime: 2020/9/7 */public class GenericDouble implements GenericIntf<Double> {}/** * Description: GenericIntf的实现类,泛型类型是Integer * * @author Xander * datetime: 2020/9/7 */public class GenericInteger implements GenericIntf<Integer> {}@Testpublic void testGeneric() {// 获取 GenericIntf接口实例的 泛型类型        GenericIntf genericInt = new GenericInteger();        GenericIntf genericDouble = new GenericDouble();        Class genericIntClass = genericInt.getGenericClass();//泛型类型是 Integer        Class genericDoubleClass = genericDouble.getGenericClass();//泛型类型是 Double        System.out.println("GenericInteger的泛型类型:" + genericIntClass);        System.out.println("genericDouble的泛型类型:" + genericDoubleClass);    }

运行结果:

GenericInteger 的泛型类型:class java.lang.IntegerGenericDouble 的泛型类型:class java.lang.Double

2.4 static 方法简单使用

java8允许接口像普通类一样定义和使用静态方法。

public interface StaticIntf {

static void printInfo() {        System.out.println("执行接口中的static方法:" + StaticIntf.class);    }}

@Testpublic void test(){// 执行接口中 static 方法        StaticIntf.printInfo();    }

运行结果:

执行接口中的static方法:interface com.xander.java8._06default_static_method.StaticIntf

结语: Optional类和接口的default、static可以作为很好的编程手段用来实现业务逻辑,Optional可以优雅地解决空指针异常,而接口的default和static方法,能够让我们定义在接口层级公共的方法,希望Java8的这两个特性能够帮助到大家。

代码:
https://github.com/wengxingxia/001java8.git

[慕课手记同步:04-Optional类和接口中的default、static方法] https://www.imooc.com/article/310370

提示: 根据相关法律法规和平台规则要求,自2018年2月12日起,新注册的微信公众帐号无法再开通留言功能。
有问题或希望交流的朋友,可以到 [慕课手记同步:04-Optional类和接口中的default、static方法] https://www.imooc.com/article/310370 下评论留言,一起学习进步。


欢迎关注公众号"黑桃"

数字类 default 0和 default 0_04Optional类和接口中的default、static方法相关推荐

  1. Java基础知识(二)(Object类的常用方法、日期时间类、System类、StringBuilder类、包装类、Collection集合、Iterator迭代器、泛型、list集Set接口...)

    文章目录 Java基础知识(二) 1.Object类的常用方法 1.1 toString方法 1.2 equals方法 1.3 Objects类 2.日期时间类 2.1 Date类 2.2 DateF ...

  2. 北京某高校可用的电话号码有以下几类,校内电话号码由4位数字组成,第1位数字不是0,校外电话又分为本市电话和外地电话两类,拨校外电话需先拨0,若是本市电话则再接着拨8位数字(第1位不是0)

    题目介绍 北京某高校可用的电话号码有以下几类: 校内电话号码由4位数字组成,第1位数字不是0: 校外电话又分为本市电话和外地电话两类,拨校外电话需先拨0, 若是本市电话则再接着拨8位数字(第1位不是0 ...

  3. java 数字翻译成英文_Java实现将数字日期翻译成英文单词的工具类实例

    本文实例讲述了Java实现将数字日期翻译成英文单词的工具类.分享给大家供大家参考,具体如下: package com.sunyard.etp.ag.util; import java.math.Big ...

  4. java 数字翻译成英文_Java实现数字日期翻译成英文单词的工具类案例分享

    这篇文章主要介绍了Java实现将数字日期翻译成英文单词的工具类,结合完整实例形式分析了Java日期转换与字符串操作相关实现技巧,需要的朋友可以参考下 本文实例讲述了Java实现将数字日期翻译成英文单词 ...

  5. C# 语言规范_版本5.0 (第10章 类)

    1. 类 类是一种数据结构,它可以包含数据成员(常量和字段).函数成员(方法.属性.事件.索引器.运算符.实例构造函数.静态构造函数和析构函数)以及嵌套类型.类类型支持继承,继承是一种机制,它使派生类 ...

  6. 设计模式(0):UML类图(Class Diagram)

    文章目录 一. 基本概念 1. 泛化(Generalization) 2. 实现(Realization) 3. 关联(Association) 4. 聚合(Aggregation) 5. 组合(Co ...

  7. 数字基带部分响应matlab,第Ⅰ类部分响应系统的抗噪声性能分析与仿真

    第Ⅰ类部分响应系统的抗噪声性能分析与仿真 陈海英 (漳州师范学院物理与电子信息工程系,福建 漳州363000) 摘要:分析了第Ⅰ类部分响应系统的抗噪声性能,并利用MATLAB软件仿真计算不同信噪比下的 ...

  8. ASP.NET2.0中的ClientScriptManager 类用法—如何添加客户端事件!

    在ASP.NET2.0中,ClientScriptManager 类通过键 String 和 Type 唯一地标识脚本.具有相同的键和类型的脚本被视为重复脚本.因此,我们可以使用脚本类型来避免混淆可能 ...

  9. ASP.NET2.0中的ClientScriptManager 类用法—如何添加客户端事件

    在ASP.NET2.0中,ClientScriptManager 类通过键 String 和 Type 唯一地标识脚本.具有相同的键和类型的脚本被视为重复脚本.因此,我们可以使用脚本类型来避免混淆可能 ...

最新文章

  1. RuntimeWarning:Glyph 21435 missing from current font.
  2. python【洛谷算法题单-搜索】P1605 迷宫
  3. matplotlib 显示批量图片_chapter4-1 简单数据可视化包Matplotlib整理1
  4. 【Jmeter】压力测试工具 Jmeter 使用
  5. 数学课本上的几大变态之处
  6. 【dfs】栅栏的木料(2012特长生 T4)
  7. 虚拟机安装mac os x实战
  8. 如何让大数据分析更有效
  9. 类数组变量定义与初始化
  10. e480win7显卡驱动_win7系统联想e480安装的操作方法
  11. 每日新闻丨阿里巴巴香港IPO指引价每股176港元左右;全球超级计算机500强榜单出炉...
  12. C++QT13位时间戳转换成年月日时分秒毫秒
  13. Java添加一个滑动验证码,有啥可难的,分分钟加一个
  14. css如何设置背景颜色透明?css设置背景颜色透明度的两种方法介绍
  15. 宝塔面板网站一打开cpu百分百_解决宝塔面板CPU占满100%,负载100%网站缓慢等问题(完全篇)...
  16. Wav音频文件剪切指定片段(限PCM格式)
  17. NLP - 微信好友个性签名情感分析( 基于Python开源库snownlp )
  18. openwrt - 性能监控 netdata
  19. revit开发__电缆桥接截面分布
  20. Vislight光源

热门文章

  1. [家里蹲大学数学杂志]第387期一套实变函数期末试题参考解答
  2. Android基础之用Eclipse搭建Android开发环境和创建第一个Android项目(Windows平台)...
  3. 飞鸽传书从微软官网上了解到微软正在推动虚拟化
  4. 做 局域网聊天 的人越来越多了
  5. 助力飞鸽传书高效沟通
  6. Facebook的规模还在继续扩大
  7. 『飞鸽』彻底学通string.Format以及IFormattable,IFormatProvider,ICustomFormatter
  8. Dell Caps Lock 切换大小写被窃取焦点问题解决办法
  9. 商业智能常见名词浅释(转载)
  10. 现在的编程语言越来越多,为什么 C 和 C++ 还没有被现在的时代淘汰呢?