1、Optional
⑴ 概念
Optional<T>
是一个容器类,可以表示一个值存在或者不存在,它里面有一个value属性用于指向传入的对象,一定程度上可以避免空指针异常
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
⑵ API
⒈ of
public static <T> Optional<T> of(T value) {}
创建一个新的Optional容器对象,里面封装了传入的对象。注意:不能传递null值,否则会报NPE
⒉ ofNullable
public static <T> Optional<T> ofNullable(T value) {}
可以创建一个新的空的Optional容器对象,即可以传入null值。注意:空的Optional,在调用get方法获取值时,会抛出java.lang.NuSuchElementException
⒊ empty
public static<T> Optional<T> empty() {}
创建一个空的Optional容器对象
⒋ get
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
获取Optional中的值
⒌ orElse
public T orElse(T other) {}
如果Optional里面没有封装值,则返回此方法传入的值
⒍ orElseGet
public T orElseGet(Supplier<? extends T> other) {}
如果Optional里面没有封装值,则返回此方法传入的供给型函数所返回的值
⒎ isPresent
public boolean isPresent() {
return value != null;
}
判断Optional中是否包含值
⒏ map
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {}
根据传入的函数式接口,返回对应数据类型(返回结果的类型或其子类)和封装了结果的Optional容器对象
⒐ flatMap
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {}
根据传入的函数式接口,返回对应数据类型(Optional,泛型为返回结果的类型)和封装了结果的Optional容器对象
⑶ 示例
Optional<String> optional = Optional.of("Hello");
optional = optional.map((val) -> {return val.length() > 2 ? "Hi" : val;});
System.out.println(optional.get());
public class Person {
private String name;
}
Optional<Person> optional = Optional.of(new Person("小明"));
Optional<String> name = optional.flatMap((p) -> {return Optional.of(p.getName());});
System.out.println(name.get());
2、重复注解和类型注解
⑴ 重复注解
⒈ 概念
JDK8允许同一个注解可以重复注释
⒉ API
需要编写一个属性值为目标重复注解数组的注解,同时在目标重复注解上使用@Repeatable注解,将含有注解数组的注解传入即可
注意:含有重复注解数组的注解的修饰目标(@Target)和运行存在时期(@Retention)都要一致,否则会报错
⒊ 示例
【重复注解】
@Repeatable(RepeatAnnotation.class) // 含有重复注解数组属性的注解
@Target(METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
【含有注解数组的注解】
@Target(METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatAnnotation {
MyAnnotation[] value();
}
【测试类】
public class TestAnnotation {
@MyAnnotation("张三")
@MyAnnotation("李四")
public void method() { }
public static void main(String[] args) {
Class<TestAnnotation> clazz = TestAnnotation.class;
Method method = null;
try {
method = clazz.getDeclaredMethod("method");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if (null != method) {
MyAnnotation[] annotations = method.getDeclaredAnnotationsByType(MyAnnotation.class); // 获取注解数组
for (int i = 0, len = annotations.length; i < len; i++) {
System.out.println(annotations[i].value());
}
}
}
}
⑵ 类型注解
JDK8允许在方法形参前添加注解,在@Target中使用ElementType.TYPE_PARAMETER
3、接口的默认方法和静态方法
⑴ 默认方法
⒈ 概念
JDK8中允许接口中包含有具体实现的方法(可以有多个),该方法被称为默认方法,通过default关键字来修饰
⒉ 示例
public interface MyInterface {
default String hello(String name) {
return "Hello:" + name;
}
}
⑵ 类优先原则
⒈ 概念
如果一个类同时继承了父类,实现了接口,而父类和接口中的默认方法同名时,则子类调用方法,优先使用父类的方法
⒉ 示例
【父类】
public class SuperClass {
public String hello() {
return "你好!";
}
}
【接口】
public interface MyInterface {
default String hello() {
return "Hello!";
}
}
【子类】
public class SubClass extends SuperClass implements MyInterface { }
【测试】
SubClass subClass = new SubClass();
String hello = subClass.hello();
System.out.println(hello); // 你好!
⑶ 接口冲突
⒈ 概念
当实现的多个接口中,含有相同的默认方法,则需要实现类来指定要调用哪个接口的默认方法
使用接口.super.方法名来指定
⒉ 示例
【接口1】
public interface MyInterface {
default String hello() {return "Hello!";}
}
【接口2】
public interface MyInterface2 {
default String hello() {return "Hi!";}
}
【实现类】
public class SubClass implements MyInterface, MyInterface2 {
@Override
public String hello() {
return MyInterface2.super.hello(); // 调用接口MyInterface2的默认方法
}
}
【测试】
SubClass subClass = new SubClass();
String hello = subClass.hello();
System.out.println(hello); // Hi!
⑷ 静态方法
⒈ 概念
JDK8中还允许接口中包含静态方法(可以有多个)
⒉ 示例
public interface MyInterface {
static void hi() {
System.out.println("Hi");
}
}