JAVA学习之java8 optional

来源:互联网 发布:俄罗斯姑娘知乎 编辑:程序博客网 时间:2024/06/06 09:55

我们都知道java中最容易出现的异常就是NullPointException异常,而且这种异常是由于我们写代码的不严谨造成的,比如我们通过id查询数据库的一条学生记录,返回Student对象,那么我们在获取学生相关属性的时候就会出现以下代码,

Student student = 根据学生编号查询数据库;String studentName = Student.getStudentName();

写出以上代码之后我们可能觉得没问题,自己测试的时候也没问题,然后我们觉得代码是完美的,但是这就是系统存在的一种bug隐患,当问题出现的时候我们费劲力气才找出问题所在,原来如上代码中的student会出现null的情况(比如该记录被逻辑删除或者学生被停用又或者有人真的删除数据库的这条记录),导致出现NullPointException这样的异常。
当我们发现问题之后,我们赶紧再我们的代码中加入如下判断

Student student = 根据学生编号查询数据库;if(null != sutdent){    String studentName = Student.getStudentName();}

好了,到处我们解决了我们的问题,但是java8的出现可以很好的避免我们的程序中出现NullPointException异常,我们可以使用Optional来包裹我们的可能为空的对象,看看如下代码

package com.java8.time;/** * Created by Administrator on 2017/4/4. */public class Student {    private Integer id;    private String name;    private Integer age;    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public static String sayHello(Student student) {        return "testOptional";    }    public String testStudent(Student student){        return "22222222";    }    public String test(){        return "2222";    }}
package com.java8.time;import java.util.Optional;/** * Created by Administrator on 2017/4/3. */public class OptionalTest {    public static void main(String[] args) {        Student student = new Student();        //方式一、对象实例方法        Optional.ofNullable(getStudent()).map(student::testStudent);        //方式二、类静态方法        Optional.ofNullable(getStudent()).map(Student::sayHello);        //方式三、某种类型所有对象的实例方法(类型代表Student类型)        Integer id = Optional.ofNullable(getStudent()).map(Student::getId).orElse(100001);        String name = Optional.ofNullable(getStudent()).map(Student::getName).orElse("smile");        System.out.println(String.format("编号:%d,姓名:%s", id, name));    }    public static Student getStudent(){        Student student = null;        return student;    }}

如上代码我们可以先忽略方法一和方法二的实现方式,我们只需要关系方法三的实现方式,代码中我们没有通过判空同样可以解决NullPointException异常,而且我们的代码看起来很简洁,这就是java8的追求,避免为了获取一个对象属性我们需要不断的通过if判空来实现。
那么既然我们使用了Optional,那就必须了解Optional的实现以及它拥有那些我们可以使用的方法

//包裹我们的对象,但是该value不能为null,因为调用的构造里面对value进行非空验证,如果为null直接抛出异常public static <T> Optional<T> of(T value) {    return new Optional<>(value);}//同样作为包裹我们的对象,该value可以为空,如果为空的话构造一个Optional对象,其属性value为nullpublic static <T> Optional<T> ofNullable(T value) {    return value == null ? empty() : of(value);}//如果Optional对象的value存在,提供一个消费者来进行消费public void ifPresent(Consumer<? super T> consumer) {    if (value != null)        consumer.accept(value);}//如果Optional对象的value存在,进行一些过滤操作public Optional<T> filter(Predicate<? super T> predicate) {    Objects.requireNonNull(predicate);    if (!isPresent())        return this;    else        return predicate.test(value) ? this : empty();}//如果Optional对象的value存在,进行mapping操作,不存在返回value为null的Optionalpublic<U> Optional<U> map(Function<? super T, ? extends U> mapper) {    Objects.requireNonNull(mapper);    if (!isPresent())        return empty();    else {        return Optional.ofNullable(mapper.apply(value));    }}> //如果Optional对象的value存在,进行mapping操作,不存在返回value为null的Optional,与map不同的是,flatMap操作的Optional包裹的对象也是Optional,也就是value的类型为Optionalpublic<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {    Objects.requireNonNull(mapper);    if (!isPresent())        return empty();    else {        return Objects.requireNonNull(mapper.apply(value));    }}//如果value不存在,执行默认值public T orElse(T other) {   return value != null ? value : other;}//如果value不存在,通过工厂生产出我们需要的结果public T orElseGet(Supplier<? extends T> other) {    return value != null ? value : other.get();}//如果value不存在我们就跑出异常public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {    if (value != null) {        return value;    } else {        throw exceptionSupplier.get();    }}

通过以上代码,大家可以看出来Optional就是一个包裹value的容器,该value可以为null也可以不为null,但是我们进行操作的时候,比如filter、map、ifPresent、flatMap、orElse等方法的时候,都会进行判断null,如果为null什么操作也不执行,就不会出现NullPointerException异常。
那么接下来给大家讲讲OptionalTest类中方法一和方法二是怎么一回事?

在讲解之前我们来普及下java8Lambda表达式,我们随便找个函数式接口
 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {    Objects.requireNonNull(mapper);    if (!isPresent())        return empty();    else {        return Optional.ofNullable(mapper.apply(value));    }}//Function 函数式接口定义如下R apply(T t);

如上map方法接收一个Function函数接口,我们可以写成如下方式.map((一个参数) -> {return 任意类型}),也就是我们可以使用(参数列表) -> {实现},来对应函数式接口中的抽象方法,意思就是,将()中的参数作为apply方法的参数,{}中的代码作为apply方法的方法体,方法体必须返回一个值,因为apply方法返回的是R类型。
我们可以使用方法引用来代替() -> {}这样的Lambda表达式,使我们的方法更加的简单。方法应用方式就是使用::这样的标识,方法应用可以有一下几种:
①静态方法如:Person(代表的是Person类型)::getxxxx()
②实例方法如:person::getxxxx()
③某一类型所有对象实例方法如:Person(代表的是Person之一类型)::getxxxx();
④构造器如:Person::new

方法三使用的方式是某一特定类型所有实例方法
Integer id = Optional.ofNullable(getStudent()).map(Student::getId).orElse(100001);String name = Optional.ofNullable(getStudent()).map(Student::getName).orElse("smile");//以下是Optional.ofNullable的源码public static <T> Optional<T> ofNullable(T value) {    return value == null ? empty() : of(value);}//以下是map的源码,传递一个Function的函数式接口,传入T类型,返回U类型public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {    Objects.requireNonNull(mapper);    if (!isPresent())        return empty();    else {        return Optional.ofNullable(mapper.apply(value));    }}

上面代码中,Optional.foNullable(getStudent()),那么Optional的类型为Student类型,那么我们在调用map操作的时候,可以是Student类中的所有实例方法。Student类型对应Function函数式接口中的类型T,getId()方法和getName()方法返回值对应返回值U类型,说白了调用map方法,我们需要提供一个输入参数和一个方法体,方法体的放回值对应U类型。getId()返回Integer,那么U类型为Integer,getName()返回String,那么U类型为String类型
接下来讲解方法一,方法一使用的是对象的实例方法

//方式一、对象实例方法Optional.ofNullable(getStudent()).map(student::testStudent);
照着以上思路,我们需要提供输入参数T和一个带有返回值得方法体,如上testStudent(Student student),student参数对应类型T, testStudent返回值对应类型U接下来讲解方法二, 方法二使用的是静态方法
//方式二、类静态方法Optional.ofNullable(getStudent()).map(Student::sayHello);
同理,sayHello(Student student),student对应类型T,sayHello方法的返回值对应类型U
0 0
原创粉丝点击