【第三天】Optional类源码解析,方法引用详解
程序员文章站
2022-06-17 08:26:17
...
Optional(重要)
解决NPE Nullpointerexception
doc
- 一个容器对象可能包含也可能不包含非空值。如果容器存在值,isPresent()将返回true,get()将返回该值。
- 提供了依赖于是否存在包含值的其他方法,例如orElse()(如果值不存在,则返回默认值)和ifpresent()(如果值存在,则执行代码块)。
-
这是一个基于值的类;对可选实例使用标识敏感操作(包括引用相等(==)、标识哈希代码或同步)可能会产生不可预知的结果,应避免
基于值的类
某些类(例如java.util.Optional和 java.time.LocalDateTime)是基于值的。基于值的类的实例:
1.是最终的且不可变的(尽管可能包含对可变对象的引用);
具有的实现equals, hashCode和toString被仅从实例的状态计算,而不是来自它的身份或任何其他物体或变量的状态,这;
2.不使用身份敏感的操作,例如实例之间的引用相等(),实例的身份哈希码或实例的固有锁上的同步;
3.仅基于equals(),而不是基于引用相等()被视为相等;
4.没有可访问的构造函数(私有的的构造函数),而是通过工厂方法(静态方法)实例化的,该方法对提交的实例的身份不作任何承诺;
5.在相等时可以*替换,这意味着在任何计算或方法调用中互换任何两个实例x并且y根据它们相等equals()都不应在行为上产生任何可见的变化。
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
/**
* 构造一个空实例。
*/
private Optional() {
this.value = null;
}
/**
返回空的可选实例。此选项没有值
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
构造具有当前值的实例。(传过来的值要确保不为空 否则会报错)
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
/**
* 构造具有当前值不为空的实例
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
*构造了一个可能为空也可能不为空的实例
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/**
*如果此可选值中存在值,则返回该值,否则抛出NoSuchElementException
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
*如果存在值,则返回true,否则返回false。
*/
public boolean isPresent() {
return value != null;
}
/*
如果改容器的value属性存在值,则使用该值调用者指定的行为,否则不执行任何操作
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
/*
如果该容器value值为null 返回参数值
*/
public T orElse(T other) {
return value != null ? value : other;
}
/*
如果该容器value值为null 获取Supplier行为.get()值
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
/*
将Function.apply(value) 得到结果放到容器value值当中
*/
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
//value值不存在时
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
}
例Optional方法使用
public class OptionalTest {
public static void main(String[] args) {
String getID = "";
Optional<String> optional = Optional.of("hello");// 拿到了包装hello值的类
Optional<String> optional2 = Optional.empty();//构造一个为空的的Optional类
Optional<String> optional3 = Optional.ofNullable(getID);//构造一个不确定为空的的Optional类
//如果包装类的值存在
if (optional.isPresent()) {
//打印获取的值
System.out.println(optional.get());
}
//推荐使用Optional函数式编程编写
optional.ifPresent(x -> System.out.println(x)); //hello
System.out.println("==========================");
/*
如果容器value值 存在打印value值 不存在打印参数
*/
System.out.println(optional2.orElse("备用值"));//备用值
System.out.println("==========================");
System.out.println(optional2.orElseGet(() -> "nihao"));
}
}
例:如果company中有存在employee集合 返回该数据 没有返回employee空集合,以及使用规范
public class OptionalTest2 {
public static void main(String[] args) {
Employee employee = new Employee();
employee.setName("zhangsan");
Employee employee2 = new Employee();
employee2.setName("lisi");
Company company = new Company();
company.setName("company");
company.setEmployees(Arrays.asList(employee, employee2));
/*
如果company中有存在employee集合 返回该数据 没有返回employee空集合
*/
Optional<Company> optionalCompany = Optional.ofNullable(company);
System.out.println(optionalCompany.map(x -> x.getEmployees()).orElse(Collections.emptyList()));
}
/*
通常Optionnal 不用于参数和成员变量 而是用于方法的返回值用来规避空指针异常的
如果当Optionnal为成员变量时而这个类需要序列化时 Optionnal是无法序列化的会出问题
*/
public void test(Optional optional){
}
}
方法引用
理解:方法引用是lambda表达式的一个特定方式,或者说是lambda表达式的语法糖
我们将方法引用看做一个函数指针,
例
public class MethodReferenaceDemo {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "world", "function", "optional");
list.forEach(x -> System.out.println(x));
/*
我们点击::(java8新增的一种语法格式)他们跳转到 forEach 传的行为参数接口
方法引用顾名思义
我们可以理解为它将 传过来的参数 自动指向Consumer函数
每个参数去执行System.out 的println方法的这个行为 其实就是(x -> System.out.println(x)
*/
list.forEach(System.out::println);
}
}
方法引用共分为4类:
- 类名::静态方法
实例
public class MethodReferenaceTest {
public static void main(String[] args) {
Student student1 = new Student("zhangsan", 100);
Student student2 = new Student("lisi", 10);
Student student3 = new Student("wangwu", 40);
Student student4 = new Student("liliu", 50);
List<Student> list = Arrays.asList(student1, student2, student3, student4);
//将list集合按照指定方法排序
list.sort((x, y) ->
Student.compareStudentByScore(x, y));
list.forEach(x -> System.out.println(x));
System.out.println("=============");
/*
采用静态方法引用的方式 类名::静态方法
compareStudentByScore静态方法恰好跟参数接口入参和返回值完全一致
就可以看做 是他的行为动作
*/
list.sort(Student::compareStudentByScore);
list.forEach(x -> System.out.println(x));
}
/*
Student.compareStudentByScore(x, y) 与 Student::compareStudentByScore 的区别?
第一种是方法调用 jdk1.8 之前 需要传入参数 得到指定结果
第二种是方法引用 jdk1.8 之后 不需要 传入参数 通过 静态方法引用得到结果 两者完全不一样
*/
}
-
引用名::实例方法名
基于上例
新增StudentReferenace 类
public class StudentReferenace {
public int compareStudentByScore(Student student1, Student student2) {
return student1.getScore() - student2.getScore();
}
public int compareStudentByScore2(Student student1, Student student2) {
return student1.getUsername().compareTo(student2.getUsername());
}
}
public class MethodReferenaceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan", 100);
Student student2 = new Student("lisi", 10);
Student student3 = new Student("wangwu", 40);
Student student4 = new Student("liliu", 50);
List<Student> list = Arrays.asList(student1, student2, student3, student4);
//类似静态方法引用 不过使用方法必须实例化
StudentReferenace st = new StudentReferenace();
//将list集合按照指定方法排序
list.sort((x, y) ->
st.compareStudentByScore(x, y));
list.forEach(x -> System.out.println(x.getScore()));
System.out.println("=============");
/*
采用静态方法引用的方式 类名::静态方法
compareStudentByScore静态方法恰好跟参数接口入参和返回值完全一致
就可以看做 是他的行为动作
*/
list.sort(st::compareStudentByScore);
list.forEach(x -> System.out.println(x.getUsername()));
}
}
上一篇: 容器