zoukankan      html  css  js  c++  java
  • java8 Optional理解及示例

    大量判空的代码

    实际中,对象不判空会导致空指针异常。

    为了规避为指针,不得不写出这种非常冗长又丑陋的空指针判断。

    public void tooMuchNull(Worker worker) {
    	if (worker != null) {
    		Address address=worker.getAddress();
    		if (address != null) {
    			String city=address.getCity();
    		}
    	}
    }
    

    Optional<T>

    Optional<T>包含的对象value可能非null,也可能为null。

    常建的构建Optional<T>对象的方法,有ofNullable(T value)、of(T value)。

    构建时,最终都会调用Optional的构造方法Optional(T value)。

    而常见的判断Optional结果的方法有,orElse()、ifPresent()、get()、empty()、map()、flatMap()。

    api图

    如下图所示:

    代码示例:

    • orElse():
    /**
     * orElse(默认值),如果Optional<T>封装的对象不存在值,则返回默认值。
     */
    public void orElseDemo() {
    //		Worker worker1=new Worker("123",18,"lin");
    	Worker worker1 = null;
    	Worker worker2 = new Worker("456", 28, "chen");
    	//如果worker1不为null,则orElse返回worker1,否则返回默认值worker2
    	Worker result = Optional.ofNullable(worker1).orElse(worker2);
    	//相当于以下代码:
    //		if (worker1 != null) {
    //			result = worker1;
    //		} else {
    //			result = worker2;
    //		}
    	System.out.println(result.getName() + "," + result.getAge());
    }
    
    • orElseGet():
    /**
     * orElseGet(),如果Optional<T>封装的对象不存在值,则执行Supplier函数式。
     * orElseGet(Supplier<? extends T> other),返回的类型必须和Optional封装的对象类型一致。
     */
    public void ofElseGetDemo() {
    	String name1 = null;
    	String name2 = "lin";
    	//orElseGet(Supplier<? extends T> other),返回的类型必须和Optional封装的对象类型一致。
    	String result = Optional.ofNullable(name1).orElseGet(this::supplier);
    	System.out.println(result);
    }
    
    public String supplier() {
    	return "orElseGet(Supplier)";
    }
    
    • of():
    /**
     * of(对象),如果封装的对象为空,则会报出空指针异常
     */
    public void ofDemo() {
    //		Worker worker1=new Worker("123",18,"lin");
    	Worker worker1 = null;
    	Worker worker2 = new Worker("456", 28, "chen");
    	Worker result = Optional.of(worker1).orElse(worker2);
    	System.out.println(result.getName() + "," + result.getAge());
    }
    
    • isPresent():
    /**
     * isPresent()表示如果Optional<T>封装的对象不为空,就返回true。
     */
    public void isPresentDemo() {
    	Worker worker1 = new Worker("123", 18, "lin");
    	Optional<Worker> workerOpt = Optional.ofNullable(worker1);
    	//这种写法比较丑,可以直接用下面的ifPresent()方法代替。
    	boolean isPresent = workerOpt.isPresent();
    	if (isPresent) {
    		System.out.println(workerOpt.get().getName());
    	}
    	//以上代码,相当于:
    //		if (worker1 != null) {
    //			System.out.println(worker1.getName());
    //		}
    }
    
    • ifPresent(lambda):
    /**
     * ifPresent(lambda)表示如果对象不为null,则会执行对应的lambda语句。
     */
    public void ifPresentDemo() {
    //		Address address=new Address("中国","广东","深圳");
    //		Worker worker1=new Worker("123",18,"lin",address);
    	Worker worker1 = new Worker("123", 18, "lin");
    //		Worker worker1=null;
    	List<String> nameList = new ArrayList<>();
    	Optional.ofNullable(worker1).ifPresent(worker -> nameList.add(worker.getName()));
    	//上面这句代码的作用相当于以下注释的代码:
    //		if (worker1 != null) {
    //			nameList.add(worker1.getName());
    //		}
    	nameList.forEach(System.out::println);
    }
    
    
    • map(lambda):

    map的参数里面是lambda表达式,会从Optional对象中进行映射,提取和转换值。

    public  void mapDemo() {
        String str=" test ";
        Optional.ofNullable(str).map(String::trim)
    	.filter(t -> t.length()> 1)
    	.ifPresent(s->{
    	    s+="1234";
    	    System.out.println(s);
    	});
    //相当于以下代码:
    //	if (str != null) {
    //	    str=str.trim();
    //	    if (str.length() > 1) {
    //		str+="1234";
    //		System.out.println(str);
    //	    }
    //	}
    }
    
    • flatMap(lambda):

    flatMap()的参数是lambda表达式,返回值是Optional。

    /**
     * flatMap(),如果Optional封装对象不为空,就会执行对应的mapping函数,返回Optional类型的值,否则就返回一个空的Optional对象。
     * 通过flatMap(),可以不断地返回Optional对象,一直进行链式调用。非常重要~
     */
    public void flatMapDemo() {
    	Address address = new Address("中国", "广东", "深圳");
    	Worker worker = new Worker("123", 18, "lin", address);
    	String city = Optional.ofNullable(worker)
    			.flatMap(Worker::getAdress)
    			.flatMap(Address::getCity)
    			.orElse("default");
    	System.out.println(city);
    }
    
    • orElseThrow():
    /**
     * orElseThrow(),如果Optional封装的对象为空,就会抛出对应的异常。
     */
    public void orElseThrowDemo() {
    //		Worker worker = new Worker("123", 18, "lin");
    	Worker worker = null;
    	Worker result = Optional.ofNullable(worker)
    			.orElseThrow(IllegalArgumentException::new);
    	System.out.println(result.getName());
    }
    
    • filter(lambda):
    public void filterDemo() {
    	Worker worker = new Worker("123", 18, "lin");
    	Optional<Worker> result = Optional.ofNullable(worker)
    			.filter(worker1 -> worker1.getAge() > 20);
    	//如果符合条件(比如,年龄大于20)则为true,不符合则为false
    	System.out.println(result.isPresent());
    }
    

    区别:

    • of() 和 ofNullable() 的区别:

    这两个方法都可以创建包含值的 Optional。
    不同之处在于如果你把 null值作为参数传递进ofNullable(),而传递null作为参数时,of() 方法会抛出 NullPointerException。

    • orElse()和orElseGet()的区别:
      orElse(默认值),表示如果有值则返回该值,否则返回传递给它的默认值。

    orElseGet(lambda表达式)会在有值的时候返回值,如果没有值,它会执行作为参数传入的函数式接口(返回类型必须和Optional封装的对象是同一种类型),并将返回其执行结果。

    需要特别注意的是:

    Optional的orElse()若方法不是纯计算型的,有与数据库交互或者远程调用的,都应该使用orElseGet() 。

    orElse()无论前面Optional容器是null还是non-null,都会执行orElse里的方法,orElseGet()并不会。

    详情参见:https://blog.csdn.net/weixin_30437337/article/details/95443798

    • isPresent()和ifPresent(lambda)的区别:

    看方法名is开头,就可以知道isPresent()返回的是布尔值。而ifPresent()则是如果对应的值存在,就会执行函数式接口。

    • flatMap(lambda)和map(lambda)的区别:

    值不为空时,两者都会执行参数中的函数式接口。

    而flatMap()返回值是Optional,通过不断地产生Optional,可以进行链式调用。

    可以重构的示例:

    回头看一下开头的代码,如下:

    public void tooMuchNull(Worker worker) {
    	if (worker != null) {
    		Address address=worker.getAddress();
    		if (address != null) {
    			String city=address.getCity();
    		}
    	}
    }
    

    下面尝试用Optional改写。

    重写getter()

    重写getter,返回Optional对象。

    public class User {
        private Address address;
    
        public Optional<Address> getAddress() {
            return Optional.ofNullable(address);
        }
    
        // ...
    }
    

    优化

    重写完getter后,上面的例子,可以用Optional改写为:

    public void preventNullPointer() {
        Worker worker = new Worker("123", 18, "lin");
    
        String result = Optional.ofNullable(worker)
          .flatMap(u -> u.getAddress())
          .flatMap(a -> a.getCity())
          .orElse("default");
    
    }
    

    再进一步简写成:

    String city = Optional.ofNullable(worker)
    		.flatMap(Worker::getAdress)
    		.flatMap(Address::getCity)
    		.orElse("default");
    

    使用Optional要注意:

    • Optional 主要用作返回类型。

    • Optional不能作为入参的参数.

    • Optional不会序列化,不要直接作为对象属性。

    • Optional不要用于集合操作。空集合请使用Collections.emptyList()。

    代码地址:

    https://github.com/firefoxer1992/JavaDemo/tree/master/src/main/java/com/java8

    参考资料:

    https://www.cnblogs.com/zhangboyu/p/7580262.html

    https://juejin.im/post/5e66ecdc518825490d126a16

  • 相关阅读:
    改变Edit的光标(使用CreateCaret,ShowCaret和LoadBitmap三个API函数)
    浅析Delphi Container库(有开源的DCLX)
    Delphi接口的底层实现(接口在内存中仍然有其布局,它依附在对象的内存空间中,有汇编解释)——接口的内存结构图,简单清楚,深刻 good
    Asp.Net在多线程环境下的状态存储问题
    C#程序中注释过多的8条理由
    CentOS 6.4 编译安装LLVM3.3,Clang和Libc++
    Microsoft 2013校园招聘笔试题及解答
    代码契约CodeContract(八)
    T-SQL 临时表、表变量、UNION
    BST&AVL&红黑树简单介绍
  • 原文地址:https://www.cnblogs.com/expiator/p/12442629.html
Copyright © 2011-2022 走看看