栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

04-Optional类和接口中的default、static方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

04-Optional类和接口中的default、static方法

若想了解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 如果 Optional 的值存在而且匹配给定的 predicate(断定型函数式接口),返回当前Optional,否则返回一个空Optional(值为null)
Optional flatMap(Function> mapper) 如果 Optional 的值存在,应用提供的映射方法并返回结果 Optional,否则返回一个空的Optional
T get() 如果此 Optional 存在值,则返回值,否则抛出NoSuchElementException
int hashCode() 返回当前值的哈希码值(如果有),如果没有值,则返回0。
void ifPresent(Consumer consumer) 如果存在值,对该值应用指定的 Consumer(消费型函数式接口),否则不执行任何操作。
boolean isPresent() 如果存在值,返回true,否则返回false
Optional map(Function 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 other) 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier(供给型函数式接口)返回一个T类型的对象
T orElseThrow(Supplier exceptionSupplier) 如果此Optional的value不为null,则返回value,否则通过调用给定的Supplier创建一个Throwable
String toString() 返回非空字符串表示此Optional,适用于调试。

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

  • isPresent()方法,如果存在值,将返回true,否则返回false。
  • orElse(T other)方法,如果存在值,则返回当前Optional的value,否则返回 other
  • ifPresent(Consumer consumer),如果存在值,对该值应用指定的 Consumer,执行代码块,否则不做任何操作
1.2 Optional 源码
public final class Optional {
    
    private static final Optional EMPTY = new Optional<>();

    
    private final T value;

    
    private Optional() {
 this.value = null;
    }

    
    public static Optional empty() {
 @SuppressWarnings("unchecked")
 Optional t = (Optional) EMPTY;
 return t;
    }

    
    private Optional(T value) {
 this.value = Objects.requireNonNull(value);
    }

    
    public static  Optional of(T value) {
 return new Optional<>(value);
    }

    
    public static  Optional 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 void ifPresent(Consumer consumer) {
 if (value != null)
     consumer.accept(value);
    }

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

    
    public Optional map(Function mapper) {
 Objects.requireNonNull(mapper);
 if (!isPresent())
     return empty();
 else {
     return Optional.ofNullable(mapper.apply(value));
 }
    }

    
    public Optional flatMap(Function> mapper) {
 Objects.requireNonNull(mapper);
 if (!isPresent())
     return empty();
 else {
     return Objects.requireNonNull(mapper.apply(value));
 }
    }

    
    public T orElse(T other) {
 return value != null ? value : other;
    }

    
    public T orElseGet(Supplier other) {
 return value != null ? value : other.get();
    }

    
    public  T orElseThrow(Supplier exceptionSupplier) throws X {
 if (value != null) {
     return value;
 } else {
     throw exceptionSupplier.get();
 }
    }

    
    @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);
    }

    
    @Override
    public int hashCode() {
 return Objects.hashCode(value);
    }

    
    @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 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,否则返回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 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.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 {

    
    void accept(T t);

    
    default Consumer andThen(Consumer 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 void sayHello() {
 System.out.println("DefaultIntf say hello 2 you");
    }
}

public interface SayHelloIntf {
    
    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 {

    
    @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


public interface GenericIntf {

    
    default Class getGenericClass() {
 Type[] types = this.getClass().getGenericInterfaces();
 ParameterizedType parameterizedType = (ParameterizedType) types[0];
 Class tClass = (Class) parameterizedType.getActualTypeArguments()[0];
 return tClass;
    }
}


public class GenericDouble implements GenericIntf {
}


public class GenericInteger implements GenericIntf {
}

    @Test
    public 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.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的这两个特性能够帮助到大家。

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


转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号