欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【第三天】Optional类源码解析,方法引用详解

程序员文章站 2022-06-17 08:26:17
...

Optional(重要)

解决NPE Nullpointerexception
doc

  • 一个容器对象可能包含也可能不包含非空值。如果容器存在值,isPresent()将返回true,get()将返回该值。
  • 提供了依赖于是否存在包含值的其他方法,例如orElse()(如果值不存在,则返回默认值)和ifpresent()(如果值存在,则执行代码块)。
  • 这是一个基于值的类;对可选实例使用标识敏感操作(包括引用相等(==)、标识哈希代码或同步)可能会产生不可预知的结果,应避免
    【第三天】Optional类源码解析,方法引用详解

基于值的类

某些类(例如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类:

  1. 类名::静态方法

实例

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 之后 不需要 传入参数 通过 静态方法引用得到结果 两者完全不一样
     */
}

  1. 引用名::实例方法名
    基于上例
    新增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()));

    }
}
相关标签: java8