若想了解java8其它新特性,请到 00-java8常用新特性文章索引 阅读。
这篇文章,介绍Java8的 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) |
<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper) | 如果 Optional 的值存在,应用提供的映射方法并返回结果 Optional,否则返回一个空的Optional |
T get() | 如果此 Optional 存在值,则返回值,否则抛出NoSuchElementException |
int hashCode() | 返回当前值的哈希码值(如果有),如果没有值,则返回0。 |
void ifPresent(Consumer<? super T> consumer) | 如果存在值,对该值应用指定的 Consumer(消费型函数式接口),否则不执行任何操作。 |
boolean isPresent() | 如果存在值,返回true,否则返回false |
<U>Optional<U> 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,否则返回 otherifPresent(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<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) 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 <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* 通过给定的value,返回一个值为给定value的Optional实例,value可为null,若value为null,则返回 EMPTY
*/
public static <T> Optional<T> ofNullable(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 Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
/**
* 如果值存在,对该值应用给定的映射方法,如果是非null的结果,返回一个描述该值的 optional,否则返回一个空Optional(值为null)
*/
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
/**
* 如果 Optional 的值存在,应用提供的映射方法并返回结果Optional,否则返回一个空的Optional
*/
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> 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 <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
/**
* 指示给定的对象是否 equals 此Optional的value
*/
@Override
public 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。
*/
@Override
public int hashCode() {
return Objects.hashCode(value);
}
/**
* 返回非空字符串表示此Optional,适用于调试。
*/
@Override
public 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Test
public void test() {
Person p = new Person("张三", 18);
// 通过给定的value,返回一个值为给定value的Optional实例,若value为null,则抛出NullPointerException
// Optional<Object> o = Optional.of(null);
Optional<Person> opPerson = Optional.of(p);
System.out.println("of(T value): " + opPerson);
// 通过给定的value,返回一个值为给定value的Optional实例,value可为null,若value为null,则返回 Optional.EMPTY
Optional<Person> 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,否则返回false
boolean 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<Person, String> funcGetName = value->value.getName();
Function<Person, String> funcGetName = Person::getName;
Optional<String> opNameofOpNull = opNull.map(funcGetName);
Optional<String> opNameofOpPerson = opPerson.map(funcGetName);
System.out.println("opNull.map(): " + opNameofOpNull);
System.out.println("opPerson.map(): " + opNameofOpPerson);
// 如果 Optional 的值存在,应用提供的映射方法并返回结果 Optional,否则返回一个空的Optional
Optional<Person> op1 = opNull.flatMap(value -> Optional.of(new Person("李四", 20)));
Optional<Person> 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<Person> 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<NullPointerException> 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.empty
T get(): Person{name='张三', age=18}
opNull persent: false
opNull 的 value == null
opPerson persent: true
张三的年龄是18
opNull.filter(): Optional.empty
opPerson.filter() 匹配age==18: Optional[Person{name='张三', age=18}]
opPerson.filter() 匹配age==19: Optional.empty
opNull.map(): Optional.empty
opPerson.map(): Optional[张三]
opNull.flatMap(): Optional.empty
opPerson.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类
:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* 这就是一个default方法
*/
default Consumer<T> andThen(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 {
@Override
public 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方法进行重写,则编译出错。子类中必须必须覆盖该方法来解决冲突。
*/
@Override
public void sayHello() {
System.out.println("Hello this is Fish");
}
}
@Test
public 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 you
Hello I am Cat sayHello
Animal say hello
Hello this is Fish
2.3 项目实战场景
获取接口实例的泛型Class
/**
* Description: 接口:包含一个default方法,该接口所有的实例都可以通过该default获取泛型类型
*
* @author Xander
* datetime: 2020/9/7
*/
public interface GenericIntf<T> {
/**
* 默认方法:获取泛型T的 Class<T>
*
* @return
*/
default Class<T> getGenericClass() {
Type[] types = this.getClass().getGenericInterfaces();
ParameterizedType parameterizedType = (ParameterizedType) types[0];
Class<T> tClass = (Class<T>) 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> {
}
@Test
public void testGeneric() {
// 获取 GenericIntf接口实例的 泛型类型
GenericIntf<Integer> genericInt = new GenericInteger();
GenericIntf<Double> genericDouble = new GenericDouble();
Class<Integer> genericIntClass = genericInt.getGenericClass();//泛型类型是 Integer
Class<Double> genericDoubleClass = genericDouble.getGenericClass();//泛型类型是 Double
System.out.println("GenericInteger的泛型类型:" + genericIntClass);
System.out.println("genericDouble的泛型类型:" + genericDoubleClass);
}
运行结果:
GenericInteger 的泛型类型:class java.lang.Integer
GenericDouble 的泛型类型:class java.lang.Double
2.4 static 方法简单使用
java8允许接口像普通类一样定义和使用静态方法。
public interface StaticIntf {
static void printInfo() {
System.out.println("执行接口中的static方法:" + StaticIntf.class);
}
}
@Test
public void test(){
// 执行接口中 static 方法
StaticIntf.printInfo();
}
运行结果:
执行接口中的static方法:interface com.xander.java8.\\_06default\\_static\\_method.StaticIntf
结语: Optional类和接口的default、static可以作为很好的编程手段用来实现业务逻辑,Optional可以优雅地解决空指针异常,而接口的default和static方法,能够让我们定义在接口层级公共的方法,希望Java8的这两个特性能够帮助到大家。