详解JAVA中的OPTIONAL

详解JAVA中的Optional

Java中的Optional是Java8中新增的类,用于解决空指针异常。Optional类通过包装对象的形式,判断对象是否为空,从而避免空指针异常。

Optional基本概念

Optional的创建

Optional的创建有两种方法:empty()和of(T value)。

当要创建一个空的Optional对象时,可以使用empty方法:

Optional<String> emptyOptional = Optional.empty(); // 创建一个空的Optional对象

当要创建一个非空的Optional对象时,可以使用of方法:

String str = "Hello";
Optional<String> nonEmptyOptional = Optional.of(str); // 创建一个非空的Optional对象

如果使用of方法时,传入的对象为null,则会抛出NullPointerException。

判断Optional是否为空

Optional类提供了isPresent()和isEmpty()两个方法来判断Optional是否为空。

Optional<String> strOptional = Optional.ofNullable("Hello");
if (strOptional.isPresent()) {
    System.out.println(strOptional.get());
}

Optional<String> emptyOptional = Optional.empty();
if (emptyOptional.isEmpty()) {
    System.out.println("This Optional is empty.");
}

获取Optional中的值

Optional类提供了get()方法来获取Optional中的值。如果Optional中的对象为空,调用get()方法会抛出NoSuchElementException。

Optional<String> strOptional = Optional.ofNullable("Hello");
if (strOptional.isPresent()) {
    System.out.println(strOptional.get());
}

Optional<String> emptyOptional = Optional.empty();
try {
    emptyOptional.get();
} catch (NoSuchElementException e) {
    System.out.println("This Optional is empty.");
}

设置默认值

Optional类提供了orElse(T other)和orElseGet(Supplier<? extends T> other)两个方法,用于在Optional为空时返回默认值。

orElse方法返回一个默认值,如果Optional不为空,返回Optional的值;orElseGet方法根据传入的Supplier返回一个默认值。

Optional<String> strOptional = Optional.empty();
String result = strOptional.orElse("Default value");
System.out.println(result); // 输出:Default value

Optional<String> nonEmptyOptional = Optional.of("Non-empty value");
String result2 = nonEmptyOptional.orElse("Default value");
System.out.println(result2); // 输出:Non-empty value

orElse方法在Optional为空时,会返回指定的默认值;orElseGet方法在Optional为空时,会调用Supplier提供默认值。与orElse方法相比,orElseGet方法更适合于获取成本较高的默认值。

Optional<String> strOptional = Optional.empty();
String expensiveDefault = expensiveComputation(); // 模拟计算成本较高的默认值
String result = strOptional.orElseGet(() -> expensiveDefault);
System.out.println(result); // 输出计算得到的默认值

抛出异常

Optional类提供了orElseThrow()方法,用于在Optional为空时,抛出指定的异常。

Optional<String> strOptional = Optional.empty();
strOptional.orElseThrow(IllegalArgumentException::new); // 抛出IllegalArgumentException异常

Optional在业务中的使用

示例一:使用Optional避免空指针异常

假设有一个Person类包含了name和address属性,现在需要根据姓名获取该Person所在的国家。

public class Person {
    private String name;
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

public class Address {
    private String country;

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }
}

在传统方式中,如果要获取该Person所在的国家,需要先判断Person和Address对象是否为空,如下所示:

public String getCountryByName(String name) {
    Person person = findPersonByName(name);
    if (person != null) {
        Address address = person.getAddress();
        if (address != null) {
            return address.getCountry();
        }
    }
    return null;
}

如果使用Optional来改写上面的代码,代码更加简洁和安全:

public String getCountryByName(String name) {
    Optional<Person> optionalPerson = Optional.ofNullable(findPersonByName(name));
    return optionalPerson.flatMap(person -> Optional.ofNullable(person.getAddress()))
                         .map(Address::getCountry)
                         .orElse("Unknown");
}

示例二:使用Optional实现接口参数的可选性

假设有一个接口,该接口有一个必传参数和一个可选参数,为了支持可选参数,可以将可选参数包装成Optional类型。

public interface ProductService {
    int getPrice(String productName);
    int getPrice(String productName, int discount);
}

public class ProductServiceImpl implements ProductService {

    private Map<String, Integer> products = new HashMap<>();

    ProductServiceImpl() {
        products.put("phone", 1000);
        products.put("computer", 2000);
        products.put("camera", 3000);
    }

    @Override
    public int getPrice(String productName) {
        return products.getOrDefault(productName, 0);
    }

    @Override
    public int getPrice(String productName, int discount) {
        return Optional.ofNullable(products.get(productName))
                       .map(price -> price * discount / 100)
                       .orElse(products.getOrDefault(productName, 0));
    }
}

在实现getPrice方法时,使用了Optional包装可选参数discount,这样就可以在方法内部判断是否有折扣参数传入,来返回相应的价格。

最佳实践

  1. Optional不是语言特性,而是库特性,因此使用Optional时,尽量避免在类的成员变量中存储Optional类型。在需要返回Optional类型的方法中使用Optional就足够了。
  2. 将Optional看作是一种特殊的容器类型,用来存储可能为空的值。
  3. 可以使用orElse方法和orElseGet方法设置默认值,但应尽量避免调用get()方法,而是使用orElse、orElseGet等方法来获取Optional中的值。
  4. 对于集合类型,可以使用stream()和filter()方法来过滤null值。

结论

Optional类非常适合于编写的API,特别是在公开API时,Optional可以明确属性是否可能为空,从而能够更好地告知使用者。

然而,在很多情况下,使用Optional并不一定会让代码更加优雅,更加简单和清晰。因此,在使用Optional时,需要慎重考虑。

阅读剩余 76%

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解JAVA中的OPTIONAL - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Spring Boot整合持久层之JPA多数据源

    让我来为你详细讲解“Spring Boot整合持久层之JPA多数据源”的完整攻略。 1. 环境准备 本文假设你已经安装了以下软件: JDK 1.8或更高版本 MySQL数据库 Eclipse或IntelliJ IDEA等开发工具 此外,还需要引入以下依赖包: Spring Boot Starter Data JPA MySQL JDBC Driver(如果你…

    Java 2023年5月20日
    00
  • 详解Spring极速集成注解redis实录

    详解Spring极速集成注解redis实录 前言 本文主要介绍Spring如何快速集成redis并使用注解方式进行操作。本教程需要你具备基本的Spring MVC框架的了解和redis的使用知识。 正文 一、引入redis依赖 在Spring项目中引入下面的redis依赖: <dependency> <groupId>org.spri…

    Java 2023年6月3日
    00
  • Java深入浅出理解快速排序以及优化方式

    Java深入浅出理解快速排序以及优化方式 快速排序简介 快速排序是一种常用的排序算法,它的基本思想是选定一个基准数,通过递归的方式将比基准数小的值放在其左侧,比基准数大的值放在其右侧,最终达到排序的效果。快速排序的时间复杂度为O(nlogn),是一种比较快速有效的排序算法。 快速排序基本流程 选择一个基准数,例如选定数组的最后一个元素作为基准数; 遍历数组,…

    Java 2023年5月19日
    00
  • ssh项目环境搭建步骤(web项目)

    下面是ssh项目环境搭建步骤的完整攻略: 1. 需要的软件 在搭建ssh项目环境前,我们需要先安装以下软件:1. JDK:java开发环境。2. Tomcat:web应用服务器,本次攻略以Tomcat 9为例。3. MySQL:关系型数据库,本次攻略以MySQL 8.0为例。4. Maven:项目构建工具。 2. 环境设置 2.1 JDK环境变量配置 在系统…

    Java 2023年5月20日
    00
  • 解决maven打包失败:程序包xxxx不存在问题

    下面是解决”Maven打包失败:程序包xxxx不存在问题”的完整攻略: 1. 了解Maven依赖管理原理 Maven是一个流行的依赖管理工具,它通过依赖关系构建项目。当您创建一个新项目时,Maven会自动下载所需的依赖项并配置项目相应的环境。 Maven中的任何依赖都是通过坐标来定义的,包括GroupId、ArtifactId和Version三个属性。当Ma…

    Java 2023年5月20日
    00
  • Spring Security实现基于角色的访问控制框架

    为了实现基于角色的访问控制,Spring提供了一个框架:Spring Security。它可以帮助我们管理用户的认证和授权,并提供一些便利工具来实现对不同角色的访问控制。本文将介绍如何使用Spring Security来实现基于角色的访问控制,并提供两个示例来辅助理解。 一、Spring Security的概念和架构 1.1. Spring Security…

    Java 2023年5月20日
    00
  • c# 如何实现代码生成器

    实现 C# 代码生成器的方法有很多,但下面我将介绍一种比较常用的方式,主要依赖Roslyn分析器。下面是完整攻略: 1. 安装 Roslyn 的 NuGet 包 首先需要安装 Roslyn 的 NuGet 包:Microsoft.CodeAnalysis.CSharp。可以在 Visual Studio 的 NuGet 面板中搜索该包进行安装。安装成功后,你…

    Java 2023年5月19日
    00
  • 解析Tomcat的启动脚本–catalina.bat

    下面是对“解析Tomcat的启动脚本–catalina.bat”的完整攻略: 1. 什么是catalina.bat catalina.bat是Tomcat的启动脚本之一,是用于启动Tomcat服务器的批处理文件,位于Tomcat的bin目录下。该脚本通过执行一系列命令和设置环境变量的操作来启动Tomcat服务器。 2. catalina.bat的主要内容 …

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部