Optional
Optional
是一个独立的类型,在实际应用中,主要是为了解决NullPointerException
。
基于值的类
Optional类为终态类(class 前有 final修饰)
Optional是基于值的类(Value-based Classes)
(还有LocalDateTime),对于基于值的类有以下特点
- 是final不可变的(但是有可能存在可变对象的引用)
- 有hashcode和toString的实现,但是这些实现仅仅是根据实例本身的状态,不会依赖于其他的变量
- 不会使用身份敏感的操作例如“==” ,或者hashcode或者锁等。
- 仅仅依靠equals方法来判断相等性
- 不会拥有可访问的构造方法,通过工厂方法来创建的,工厂方法并不保证实例的一致性
- 当相等时是可以任意替换的。
Optional的构造方法
- empty():构造一个容器内容为空的Optional
- of():直接new一个内容为T的Optional,调用者需确保T不能为空,否则抛出空指针异常。
- ofNullable():构造一个可能为null也可能不为null的对象,如果T为null,则调用empty,否则调用of
Optional的基本使用
Optional optional = Optional.of("hello");
// 面向对象风格的写法(不推荐)
if(optional.isPresent()){
System.out.println(optional.get())
}
// 通过函数式风格
optional.ifPresent(i -> System.out.println(optional.get()));
如果不在optional.get()方法外不使用isPresent,idea会提示警告,如果Optional的内容为空,get方法会抛出异常。
orElse(T)
optional.orElse("T");
如果内容为空,则将内容指定为T,否则不做任何的改变。
避免集合的空判断
Person person = new Person();
List strings = new ArrayList<>();
person.setList(strings);
Optional.ofNullable(person).map(item -> item.getList()).orElse(Collections.emptyList());
Optional作为方法参数
public void test(Optional optional){
}
此时idea会提示警告,Optional是没有序列化的,不要作为变量传入,应该使用函数式的方式来传入。
方法引用(method reference)
在什么时候可以使用方法引用: 仅仅当lambda表达式里的实现能恰好被一个方法引用所表示,但是很多情况下lambda内容是较为复杂的。所以方法引用算是Lambda表达式的一个语法糖。
方法引用的简单使用
List list = Arrays.asList("1", "2", "3");
list.forEach(System.out::println)
我们可以将方法引用看作是一个函数指针(function pointer)
(C中的概念,将指针指向一个函数)。
方法引用的要求:你所实现的lambda方法体,恰好有一个方法完成同样的事情:同样的参数和返回值,同样的功能逻辑。
方法引用共分为4类:
-
类名::静态方法
: 引用名::实例方法名
类目::实例方法名
构造方法引用,类名::new
其中类目::实例方法名
这个并不容易理解,例如
public class Person {
private Integer age;
private String name;
public int compareName(Person person){
return this.name.compareToIgnoreCase(person.getName());
}
}
public class Test {
public static void main(String[] args) {
Person person1 = new Person();
person1.setName("abc");
Person person2 = new Person();
person2.setName("zdf");
List list = Arrays.asList(person1, person2);
list.sort(Person::compareName);
list.forEach(i -> System.out.println(i.getName()));
}
}
sort方法接受的是两个参数的Consumer,而comaperName方法只有一个入参,但是方法引用成功。原因是这个CompareName是在Person类中实现的方法,其中的一个比较对象是这个方法的一个属性,所以默认Consumer的第一个参数即为这个类本身
默认方法
interface MyInterface1{
default void myMethod(){
System.out.println("1");
}
}
interface MyInterface2{
default void myMethod(){
System.out.println("2");
}
}
public class MyClass implements MyInterface1, MyInterface2{
@Override
public void myMethod(){
MyInterface2.super.myMethod();
}
}
接口中已经支持了默认方法实现。但是如果同时实现两个同名默认方法实现,编译器因为不知道到底使用哪一个,而会报错。这时候,必须使用重写myMethod方法,显式的告诉编译器需要选择哪个具体方法实现。
public class MyImpl1 implements MyInterface1 {
@Override
public void myMethod() {
System.out.println("aa");
}
}
public class MyClass extends MyImpl1 implements MyInterface2{
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.myMethod();
}
}
java认为实现类的优先级大于default默认方法的优先级,所以上面代码将打印aa。