详解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时,需要慎重考虑。

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

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

相关文章

  • java多线程volatile内存语义解析

    Java多线程Volatile内存语义解析 什么是Volatile 在Java多线程中,Volatile是一种关键字,用来修饰变量,用于实现多线程之间的可见性和有序性。 当一个变量被声明为Volatile时,Java虚拟机保证每个线程修改了这个变量后,其他线程能够立即看到修改的结果,即保证了可见性。此外,Volatile还会影响指令和执行顺序,保证了有序性。…

    Java 2023年5月19日
    00
  • 关于servlet向mysql添加数据时中文乱码问题的解决

    当使用servlet向mysql添加数据时,中文可能会出现乱码问题。本文将详细介绍如何解决这个问题。 解决方案一:设置编码 在servlet中,我们可以通过以下方法来设置请求和响应的编码: request.setCharacterEncoding("UTF-8"); response.setContentType("text/h…

    Java 2023年5月20日
    00
  • Jsp页面实现文件上传下载类代码第1/2页

    “Jsp页面实现文件上传下载类代码”是一个常见的需求,本篇攻略将为大家详细讲解如何实现这一操作。 第1页:文件上传 1. 在前端页面中添加上传文件的表单 首先,在前端页面中添加一个上传文件的表单,用户可以通过该表单上传文件。例如: <form action="upload.jsp" method="post" e…

    Java 2023年6月15日
    00
  • struts2+spring+ibatis框架整合实现增删改查

    搭建struts2+spring+ibatis框架整合需要考虑以下几个步骤: Maven配置和相关依赖 数据库配置和数据源配置 配置Spring与Mybatis整合 配置Spring与Struts2框架整合 下面将逐步为您演示搭建struts2+spring+ibatis框架整合的完整攻略,并提供2条示例。 1. Maven配置和相关依赖 在pom.xml文…

    Java 2023年5月20日
    00
  • Java Apache Commons报错“JexlException”的原因与解决方法

    当使用Java的Apache Commons类库时,可能会遇到“JexlException”错误。这个错误通常由以下原因之一起: 语法错误:如果表达式中存在语法错误,则可能会出现此错误。在这种情况下,需要检查表达式以决此问题。 上下文错误:如果表达式上下文不正确,则可能会出现此错误。在这种情况下,需要检查表达式上下文以决此问题。 以下是两个实例: 例1 如果…

    Java 2023年5月5日
    00
  • java定时调度器(Quartz)使用实例

    Java定时调度器(Quartz)使用实例 1 什么是Quartz Quartz是一款基于Java的开源任务调度框架,常用于解决定时任务,周期性任务等问题。Quartz拥有丰富的特性,包括支持集群、加载任务、支持CRON表达式等。 2 Quartz的基本概念 在使用Quartz之前,我们需要清楚它的一些基本概念: 调度器(Scheduler) :调度器是Qu…

    Java 2023年5月20日
    00
  • hibernate增删改查操作代码

    下面我将详细讲解 Hibernate 的增删改查操作代码的完整攻略。 首先,使用 Hibernate 进行增删改查操作需要遵循以下步骤: 配置 Hibernate 配置文件 hibernate.cfg.xml 创建 Hibernate 工厂对象 SessionFactory 创建 Session 对象 开启事务 执行相应的增删改查操作 提交事务 关闭 Ses…

    Java 2023年5月19日
    00
  • Java枚举类型enum的详解及使用

    Java枚举类型enum的详解及使用 什么是枚举类型enum Java中的枚举类型enum定义一个类,列出该类的所有实例,这些实例的值是有限的、预定义的。 是一组有名字的值的集合,它们常被用作程序中的常量或者可选择的值。 Java的枚举(enum)是一种比传统的常量更为灵活、可扩展的类型。 枚举类型enum的使用 枚举的定义 enum可以在类或者包的内部定义…

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