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();
    }

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


相关文章
|
3月前
|
安全 Java 容器
告别繁琐判空:Optional让你的Java代码更优雅
告别繁琐判空:Optional让你的Java代码更优雅
|
前端开发 Java 应用服务中间件
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
3039 0
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
|
编解码 前端开发 算法
基于OpenCV的双目摄像头测距(误差小)
首先进行双目摄像头定标,获取双目摄像头内部的参数后,进行测距;本文的双目视觉测距是基于BM算法。注意:双目定标的效果会影响测距的精准度,建议大家在做双目定标时,做好一些(尽量让误差小)。
12429 3
基于OpenCV的双目摄像头测距(误差小)
|
编解码 Android开发
Android native层实现MediaCodec编码H264/HEVC
Android平台在上层实现mediacodec的编码,资料泛滥,已经不再是难事,今天给大家介绍下,如何在Android native层实现MediaCodec编码H264/HEVC,网上千篇一律的接口说明,这里不再赘述,本文主要介绍下,一些需要注意的点,权当抛砖引玉,相关设计界面如下:
528 0
|
8月前
|
存储 算法
飞桨x昇腾生态适配方案:09_Paddle转ONNX
本节主要介绍如何将 PP-OCRv4 模型转化为 ONNX 模型,包括环境准备、模型下载、训练模型转 inference 模型及最终转为 ONNX 格式的过程。首先需安装 Paddle2ONNX 和 ONNXRuntime,接着下载并解压训练模型。通过 `export_model.py` 脚本将训练模型转化为 inference 模型,生成包含结构和参数的文件。最后使用 Paddle2ONNX 工具完成到 ONNX 格式的转换,并可选地使用 onnxslim 进行模型优化。各步骤均提供详细命令与参数说明,便于实际操作与部署。
364 9
|
安全 TensorFlow 算法框架/工具
开源大模型与闭源大模型,你更看好哪一方?
开源大模型与闭源大模型,你更看好哪一方?
|
程序员 编译器
静态分配和动态分配之间的区别是什么
【9月更文挑战第1天】静态分配和动态分配之间的区别是什么
1484 0
|
NoSQL Redis
RedisTemplate.opsForSet()用法简介并举例
RedisTemplate.opsForSet()用法简介并举例
1407 2
|
容器
springboot-自定义注解拦截ip aop和ioc
springboot-自定义注解拦截ip aop和ioc
|
NoSQL Java Redis
springboot中redis的配置
【1月更文挑战第8天】springboot中redis的配置
909 2