zoukankan      html  css  js  c++  java
  • Java8新特性——Optional类的使用(有效的避免空指针异常)

    OPtional类的使用

    概述

    到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。
    Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
    Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
    Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

    Optional类的常用方法:

    Optional.empty() : 创建一个空的 Optional 实例
    Optional.of(T t) : 创建一个 Optional 实例
    Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
    isPresent() : 判断是否包含值
    T get(): 如果调用对象包含值,返回该值,否则抛异常
    orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
    orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
    map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
    flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

    代码演示

    /**
     * 
     */
    package com.xnn.Optional;
    
    import java.util.Optional;
    
    import org.junit.Test;
    
    import com.xnn.lambda.Person;
    
    /**
     * 类(接口)描述: Optional.of(T t) : 创建一个 Optional 实例 Optional.empty()
     * :创建一个空的Optional实例 Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
     * isPresent() : 判断是否包含值 T get(): 如果调用对象包含值,返回该值,否则抛异常 orElse(T t) :
     * 如果调用对象包含值,返回该值,否则返回t orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
     * map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
     * flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
     * 
     * @author xnn 2018年10月25日下午2:12:54
     */
    public class TestOptional {
    	@Test
    	public void test() {
    		// Optional.of(T t) : 创建一个 Optional 实例,参数也可为null 表示把null封装进了OPtional容器
    		Optional<Person> optional = Optional.of(new Person("李四", 59, 6666.66));
    
    		// T get(): 如果调用对象包含值,返回该值,否则抛异常
    		Person person = optional.get();
    		System.out.println("person" + person);
    		System.out.println("===========");
    		// 参数设为null的情况 会报空指针异常
    		Optional<Person> optiona2 = Optional.of(null);
    		System.out.println(optiona2.get());
    
    	}
    	@Test
    	public void test1() {
    		// Optional.empty() :创建一个空的Optional实例
    		Optional<Person> empty = Optional.empty();
    		// 因为Optional容器里面是空的 所以报了个NoSuchElementException,这样容易定位空指针
    		// 和Optional.of(null)还不太一样。Optional.of(null).get()就报了个空指针
    		System.out.println("empty.get():" + empty.get());
    	}
    	@Test
    	public void test2() {
    		// Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
    		Optional<Object> nullable = Optional.ofNullable(null);
    		// T为null创建空实例,融合了of()方法的缺陷
    		System.out.println("nullable:" + nullable);
    	}
    	@Test
    	public void test3() {
    		Optional<Object> nullable = Optional.ofNullable(null);
    
    		// isPresent() : 判断是否包含值 nullable为空 所以返回false
    		boolean present = nullable.isPresent();
    		System.out.println("present:" + present);
    	}
    	@Test
    	public void test4() {
    		Optional<Person> optional = Optional.of(new Person("李四", 59, 6666.66));
    		// orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
    		// 就是先看optional这个容器里面有值与否 若有,则直接返回 若没有 返回T
    		Object orElse = optional.orElse(new Person());
    		System.out.println(orElse);
    
    	}
    	@Test
    	public void test5() {
    		// orElseGet(Supplier s) :如果调用对象(调用者是Optional类)包含值,返回该值,否则返回 s 获取的值
    		// 和上面不同的是这里的参数需要我们提供一个Supplier类型的函数式接口
    		// ,这样我们就可以在Lambda表达式体中写自己的逻辑没最后返回个T
    		Optional<Person> optional = Optional.of(new Person("李四", 59, 6666.66));
    		Person orElseGet = optional.orElseGet(() -> new Person());
    		// 因为optional包含的对象是有值的。所以返回new Person("李四", 59, 6666.66)
    		System.out.println("orElseGet:" + orElseGet);
    		Optional<Object> nullable = Optional.ofNullable(null);
    		// 这个nulllable时空的
    		Object elseGet = nullable.orElseGet(() -> new Person());
    		// 所以返回参数(函数式接口与返回的值,即无参构造器返回的是默认值)
    		System.out.println("elseGet:" + elseGet);
    	}
    	@Test
    	public void test6() {
    		// map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
    		Optional<Person> optional = Optional.of(new Person("李四", 59, 6666.66));
    		Optional<String> map = optional.map(Person::getName);
    		System.out.println("map:"+map);
    	}
    	@Test
    	public void test7() {
    		// flatMap(Function mapper):与 map 类似,
    		Optional<Person> optional = Optional.of(new Person("李四", 59, 6666.66));
    		//要求返回值必须是Optional  所以在参数那里 Lambda表达式的返回值用Optional包装了一层
    		Optional<String> flatMap = optional.flatMap((e) -> Optional.of(e.getName()));
    		System.out.println("flatMap"+flatMap);
    	}
    }
    

    运行结果

    nullable:Optional.empty
    present:false
    Person [name=李四, age=59, salary=6666.66, status=null]
    orElseGet:Person [name=李四, age=59, salary=6666.66, status=null]
    elseGet:Person [name=null, age=0, salary=0.0, status=null]
    map:Optional[李四]
    flatMapOptional[李四]
    

    一个小应用场景

    父亲类:

    
    package com.xnn.Optional;
    
    /**
     * 类(接口)描述:
     * @author xnn
     * 2018年10月25日下午3:21:31
     */
    public class Father {
    private Son son;
    
    public Father() {
    	super();
    }
    public Father(Son son) {
    	super();
    	this.son = son;
    }
    public Son getSon() {
    	return son;
    }
    public void setSon(Son son) {
    	this.son = son;
    }
    
    @Override
    public String toString() {
    	return "Father [son=" + son + "]";
    }
    
    }
    
    

    son 类

    
    package com.xnn.Optional;
    
    /**
     * 类(接口)描述:
     * @author xnn
     * 2018年10月25日下午3:21:51
     */
    public class Son {
    private String name;
    
    public Son() {
    	super();
    }
    public Son(String name) {
    	super();
    	this.name = name;
    }
    public String getName() {
    	return name;
    }
    public void setName(String name) {
    	this.name = name;
    }
    @Override
    public String toString() {
    	return "Son [name=" + name + "]";
    }
    
    }
    
    

    现做一个小功能 传进来一个Father对象 返回他的儿子的名字 为了确保不出现空指针异常,我们通常的做法是
    1、判断传进来的Father是否为空,若为空 什么也不做 若不为空 获取其son属性
    2、判断son是否为空 若为空 返回null 若不为空 调用son的getName()方法进行返回
    若属性太多,或者是包装的层数过多,则会导致很深的if嵌套 造成代码可读性变差
    因此 我们改变Father类 把son属性用Optional类包装

    /**
     * 
     */
    package com.xnn.Optional;
    
    import java.util.Optional;
    
    /**
     * 类(接口)描述:
     * @author xnn
     * 2018年10月25日下午3:30:00
     */
    public class Father2 {
    	
    private Optional<Son> son = 
    //保证OPtional类不为空
    Optional.empty();
    public Father2() {
    	super();
    }
    public Father2(Optional<Son> son) {
    	super();
    	this.son = son;
    }
    
    public Optional<Son> getSon() {
    	return son;
    }
    public void setSon(Optional<Son> son) {
    	this.son = son;
    }
    
    
    
    @Override
    public String toString() {
    	return "Father2 [son=" + son + "]";
    }
    
    }
    
    

    测试类

    @Test
    	public void test8() {
    		Father father =new Father();
    		//报了个空指针
    		//getSonName(father);
    		//可以用if判断语句嵌套判断 避免空指针 但若嵌套太深  代码可读性也会变差
    		Optional<Father2> optional = Optional.ofNullable(new Father2(Optional.ofNullable(new Son("小明"))));
    		System.out.println(getSonName1(optional));;
    	}
    	//需求:获取父亲的儿子的名字
    	public String getSonName(Father father) {
    		return father.getSon().getName(); 
    	}
    	//传进来的father也有可能为空   所以用Optional包装
    	public String getSonName1(Optional<Father2> optional) {
    		//若传进来的对象为空没给一个默认值,保证了传进来的对象不会为空
    		return optional.orElse(new Father2())
    		        .getSon()
    		        //这个人可能还没有儿子,若没有 默认为孙悟空   避免了getName()方法的空指针
    		        .orElse(new Son("孙悟空"))
    		        .getName();
    	}
    

    结果

    小明
    
  • 相关阅读:
    flask为blueprint增加error_handler
    solr的moreLikeThis实现“相似数据”功能
    pgsql删除重复记录
    sqlalchemy的不区分大小写比较
    logrotate运行时间指定
    远程桌面剪贴板失效的解决方法
    github上关于campbell数据采集的一些代码。
    python 学习笔记
    guestfs-python 手册
    [KVM][guestfs] 安装 guestfs-python 出错
  • 原文地址:https://www.cnblogs.com/nnxud/p/9850708.html
Copyright © 2011-2022 走看看