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()方法适用于包装对象值为空时需要抛出特定异常的场景。