101.【用了Optional,同事都表示看不懂!】(一)

简介: 101.【用了Optional,同事都表示看不懂!】

(一)、Optional

1.Optional的概念

java.util.Optional 是java8中引进的一个新的类,它可以对可能缺失的值进行建模,而不是直接将null赋值给变量

它是用来规范我们开发的API,使其语义更加的明确,使用Optional修饰的对象,表示该对象可能为null。在一定程度上避免了空指针的问题

为什么要用Optional?

java中非常讨厌的一点就是nullpoint,碰到空指针就会出错抛Exception,然后需要逐行检查是哪个对象为空,带来大量的不必要精力损耗,抛出NPE错误不是用户操作的错误,而是开发人员的错误,应该被避免,那么只能在每个方法中加入非空检查,阅读性和维护性都比较差。

2.Optional类用法

Optional类的Javadoc描述如下:这是一个可以为null的容器对象。

如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象

如果值不存在则isPresent()方法会返回false,调用get()方法会NPE

创建Optional类对象的方法:

  • Optional.of(T t) : 创建一个 Optional 实例,t必须非空
  • Optional.empty() : 创建一个空的 Optional 实例
  • Optional.ofNullable(T t):t可以为null

1、创建一个空的

//使用Optional.empty()方法创建一个空的Car类型的Optional对象。
  Optional<Student> optionalCar = Optional.empty();

2、创建一个非空值的Optional,如果car为null的话,直接抛出空指针异常(参考上面的图片)。

Car car = new Car();
 Optional<Car> car1 = Optional.of(car);

3、创建一个可以为null的Optional,该方法支持car为null,但是会在用到car的地方抛出异常,但不是空指针异常。

Car car = new Car();
   Optional<Car> car2 = Optional.ofNullable(car);

判断Optional容器中是否包含对象:

  • boolean isPresent() : 判断是否包含对象
  • void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它

获取Optional容器的对象:

  • T get(): 如果调用对象包含值,返回该值,否则抛异常
  • T orElse(T other) :如果有值则将其返回,否则返回指定的other对象
  • T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象
  • T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常

过滤:

  • Optional filter(Predicate<? super predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional

映射

  • Optional map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
  • Optional flatMap(Function<? super T, Optional> mapper):如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象

3.创建Optional类

@Test
    public void testOption() {
        // 1.声明一个空Option
        Optional<Object> empty = Optional.empty();
        // 2. 根据一个非空值创建Optional
        Student student = new Student();
        Optional<Object> of = Optional.of(student);
        // 3. 根据可接受的null 进行创建
        Student student1=null;
        Optional<Student> student11 = Optional.ofNullable(student1);
    }

4.判断Optional容器中是否包含对象

isPresent不带参数,判断是否为空,ifPresent可以选择带一个消费函数的实例。(isPresent和ifPresent一个是 is 一个是 if 注意一下哈

@Test
    public void testOption() {
        // 1. isPresent是否有值
        Student student = new Student("吉士先生",21,90);
        Optional<Student> student1 = Optional.ofNullable(student);
        if (student1.isPresent()){
            System.out.println(student.getName());
        }
        // 2. ifPresent有一个Customer匿名内部类
        student1.ifPresent(new Consumer<Student>() {
            @Override
            public void accept(Student student) {
                System.out.println(student.getName());
            }
        });
        // 3. 匿名内部类,进行lambda处理
        student1.ifPresent(s-> System.out.println(s.getName()));
    }

5.获取Optional容器的对象

@Test
    public void testOption() throws Exception {
        Student student = null;
        Optional<Student> student1 = Optional.ofNullable(student);
        // 使用get一定要注意,假如student对象为空,get是会报错的
        // java.util.NoSuchElementException: No value present
        Student student3 = student1.get();
        // 当student为空的时候,返回我们新建的这个对象,有点像三目运算的感觉
        Student student2 = student1.orElse(new Student("李明", 20, 16));
        // orElseGet就是当student为空的时候,返回通过Supplier供应商匿名内部类 创建的对象
        student1.orElseGet(new Supplier<Student>() {
            @Override
            public Student get() {
                return new Student("李明2", 21, 17);
            }
        });
        //利用Lambda 实现供应商匿名内部类   {}和return 可以被省略
        student1.orElseGet(()->new Student("李明3", 20, 16));
        // orElseThrow就是当student为空的时候,可以抛出我们指定的异常
        student1.orElseThrow(()->new Exception("抛出我们指定的异常"));
    }

6.过滤

@Test
    public void testOption() throws Exception {
        Student student = new Student("吉士先生",3,20);
        Optional<Student> os1 = Optional.ofNullable(student);
        os1.filter(new Predicate<Student>() {  // 进行过滤
            @Override
            public boolean test(Student student) {
                return student.getName().equals("吉士先生");
            }
        }).ifPresent(new Consumer<Student>() {  //假如说存在值
            @Override
            public void accept(Student student) {
                System.out.println("Ok");
            }
        });
        os1.filter((s)->s.getName().equals("吉士先生")).ifPresent(d-> System.out.println("OK"));
    }

7. 映射

Map 源码信息

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));
        }
    }
@Test
    public void testOption() throws Exception {
        Student student = new Student("吉士先生",3,20);
        Optional<Student> os1 = Optional.ofNullable(student);
        os1.map(new Function<Student, Object>() {  //如果不为空,那么就+1岁
            @Override
            public Object apply(Student student) {
                student.setAge(student.getAge()+1);
                return student;
            }
        });
        System.out.println(student);
        os1.map(s->{s.setAge(s.getAge()+1);return s;});
        System.out.println(student);
    }

这块的map说实话对lambda不是很熟练的 理解起来是很绕脑子的。

这里的map实际上就是用的Function函数,Function函数是有两个参数的,第一个是入参数据类型,第二个是返回数据类型。Function函数作用就是传入一个对象,然后返回一个对象,返回的对象类型可以自己设置。

T 就是代表实例的泛型数据类型,就是谁调用的 入参 必须跟调用者泛型的数据类型一样。

U 就是自己说了算,调用完map之后返回什么数据类型,那么U就设置什么

源码

public static Optional<Integer> stringToInt(String s) {
     try {
         return Optional.of(Integer.parseInt(s));
     } catch (NumberFormatException e) {
         e.printStackTrace();
         return Optional.empty();
     }
 }
Optional.ofNullable(props.getProperty(name))
        .flatMap(OptionalUtils::stringToInt)
        .filter(i -> i>0)
        .orElse(0);

(二)、匿名内部类

1.什么是匿名内部类?

我们都知道 Lambda 是一个匿名函数,使用Lambda可以帮我们简化匿名内部类的使用,而匿名内部类在实际开发当中并不怎么用,很多人对他的印象其实并不深,所以我们有必要先了解清楚匿名内部类。

什么是匿名内部类。

匿名内部类,就是没有名字的一种嵌套类。它是Java对类的定义方式之一。

为什么要使用匿名内部类?

在实际开发中,我们常常遇到这样的情况:一个接口/类的方法的某个实现方式在程序中只会执行一次,但为了使用它,我们需要创建它的实现类/子类去实现/重写。此时可以使用匿名内部类的方式,可以无需创建新的类,减少代码冗余

匿名内部类只可以使用在接口上吗

不是的。匿名内部类可以用在具体类、抽象类、接口上,且对方法个数没有要求

2.自定义匿名内部类实现

假设当前有一个接口,接口中只有一个方法:

package com.example.springboot01hello.dao;
public interface interface1 {
    void show();
}

为了使用该接口的show方法,我们需要去创建一个实现类,同时书写show方法的具体实现方式

package com.example.springboot01hello.dao;
public class interfaceImpl implements interface1{
    @Override
    public void show() {
        System.out.println("我是实现类");
    }
}

如果实现类InterfaceImpl全程只使用一次,那么为了这一次的使用去创建一个类,未免太过麻烦。我们需要一个方式来帮助我们摆脱这个困境。匿名内部类则可以很好的解决这个问题

我们使用匿名内部类

@Test
    public void test3(){
        interface1 interface1 = new interface1() {  //实列化一个接口
            @Override
            public void show() {
                System.out.println("这里是一个匿名内部类");
            }
        };
        interface1.show();
    }

注意:匿名内部类不能有普通的静态变量声明,只能有静态常量。


相关文章
|
Java 编译器
101.【用了Optional,同事都表示看不懂!】(三)
101.【用了Optional,同事都表示看不懂!】
50 0
|
Java 编译器
101.【用了Optional,同事都表示看不懂!】(二)
101.【用了Optional,同事都表示看不懂!】
50 0
|
SQL 缓存 自然语言处理
面试官问:为啥不建议使用 Select *?请你大声地回答他!!
面试官问:为啥不建议使用 Select *?请你大声地回答他!!
124 0
面试官问:为啥不建议使用 Select *?请你大声地回答他!!
|
SQL 缓存 自然语言处理
以后面试官问你 为啥不建议使用Select *,请你大声回答他!
以后面试官问你 为啥不建议使用Select *,请你大声回答他!
|
Python Windows
你真的看得懂报错吗?
你真的看得懂报错吗?
320 0
你真的看得懂报错吗?
|
小程序 Java
Java 8 排序的 10 个姿势,太秀了吧!同事直呼看不懂。。
Java 8 排序的 10 个姿势,太秀了吧!同事直呼看不懂。。
214 0
Java 8 排序的 10 个姿势,太秀了吧!同事直呼看不懂。。
|
SQL 缓存 自然语言处理
以后面试官问你 为啥不建议使用Select *,请你大声回答他!
以后面试官问你 为啥不建议使用Select *,请你大声回答他!
239 0
以后面试官问你 为啥不建议使用Select *,请你大声回答他!
|
消息中间件 存储 监控
好好写代码之命名篇——推敲
好好写代码之命名篇——推敲
112 0
|
存储 Java
来自三段代码的疑惑~
来自三段代码的疑惑~
116 0