Java8特性。

1、接口默认方法

​ 在JDK8之前,接口不能定义任何实现,这意味着之前所有的JAVA版本中,接口制定的方法是抽象的,不包含方法体。从JKD8开始,添加了一种新功能-默认方法。默认方法允许接口方法定义默认实现,而所有子类都将拥有该方法及实现。

​ 默认方法的主要优势是提供一种拓展接口的方法,而不破坏现有代码。假如我们有一个已经投入使用接口,需要拓展一个新的方法,在JDK8以前,如果为一个使用的接口增加一个新方法,则我们必须在所有实现类中添加该方法的实现,否则编译会出现异常。如果实现类数量少并且我们有权限修改,可能会工作量相对较少。如果实现类比较多或者我们没有权限修改实现类源代码,这样可能就比较麻烦。而默认方法则解决了这个问题,它提供了一个实现,当没有显示提供其他实现时就采用这个实现。这样新添加的方法将不会破坏现有代码。

#2、函数式接口

​ 函数式接口在Java中是指:有且仅有一个抽象方法的接口

​ 函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。

接下来给大家介绍几个常用的函数式接口,在我们接下来要学习的Lamdba表达式中大量使用。

消费者,消费数据

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

供应商,给我们产生数据

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

断言,判断传入的t是不是满足条件

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
}

函数,就是将一个数据转化成另一个数据

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

​ 我们在思考上边的代码的时候,不要胡思乱想,它们就是一组接口,和我们的普通接口一样,每个接口代表一种能力,需要子类去实现,因为它们是函数式接口,所以匿名内部类都可以写成箭头函数的形式。

#3、Optional

#(1)简介

	 Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引入的一个同名Optional类,使用Optional类可以避免显式的null值判断(null的防御性检查),避免null导致的NPE(NullPointerException)。

#(2)Optional对象的创建

Optional类提供了三个静态方法empty()、of(T value)、ofNullable(T value)来创建Optinal对象,示例如下:

// 1、创建一个包装对象值为空的Optional对象
Optional<String> optStr = Optional.empty();
// 2、创建包装对象值非空的Optional对象
Optional<String> optStr1 = Optional.of("optional");
// 3、创建包装对象值允许为空的Optional对象
Optional<String> optStr2 = Optional.ofNullable(null);

#(3)Optional 类典型接口的使用

下面以一些典型场景为例,列出Optional API常用接口的用法,并附上相应代码。

get()方法

简单看下get()方法的源码:

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

可以看到,get()方法主要用于返回包装对象的实际值,但是如果包装对象值为null,会抛出NoSuchElementException异常。

isPresent()方法

isPresent()方法的源码:

public boolean isPresent() {
    return value != null;
}

可以看到,isPresent()方法用于判断包装对象的值是否非空。下面我们来看一段糟糕的代码:

public static String getGender(Student student){
    Optional<Student> stuOpt =  Optional.ofNullable(student);
    if(stuOpt.isPresent())
    {
        return stuOpt.get().getGender();
    }

    return "Unkown";
}

这段代码实现的是第一章(简介)中的逻辑,但是这种用法不但没有减少null的防御性检查,而且增加了Optional包装的过程,违背了Optional设计的初衷,因此开发中要避免这种糟糕的使用

ifPresent()方法

ifPresent()方法的源码:

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

ifPresent()方法接受一个Consumer对象(消费函数),如果包装对象的值非空,运行Consumer对象的accept()方法。示例如下:

public static void printName(Student student){
    Optional.ofNullable(student).ifPresent(u ->  System.out.println("The student name is : " + u.getName()));
}

上述示例用于打印学生姓名,由于ifPresent()方法内部做了null值检查,调用前无需担心NPE问题。

orElse()方法

orElse()方法的源码:

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

orElse()方法功能比较简单,即如果包装对象值非空,返回包装对象值,否则返回入参other的值(默认值)。

public static String getGender(Student student){
    return Optional.ofNullable(student).map(u -> u.getGender()).orElse("Unkown");
}

orElseGet()方法

orElseGet()方法的源码:

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

orElseGet()方法与orElse()方法类似,区别在于orElseGet()方法的入参为一个Supplier对象,用Supplier对象的get()方法的返回值作为默认值。如:

    public static String getGender(Student student)
    {
        return Optional.ofNullable(student).map(u -> u.getGender()).orElseGet(() -> "Unkown");      
    }

orElseThrow()方法

orElseThrow()方法的源码:

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

​ orElseThrow()方法其实与orElseGet()方法非常相似了,入参都是Supplier对象,只不过orElseThrow()的Supplier对象必须返回一个Throwable异常,并在orElseThrow()中将异常抛出:

public static String getGender1(Student student){
    return Optional.ofNullable(student).map(u -> u.getGender()).orElseThrow(() -> new RuntimeException("Unkown"));      
}

orElseThrow()方法适用于包装对象值为空时需要抛出特定异常的场景。

猜你喜欢

转载自blog.csdn.net/qq_44872509/article/details/130632860