Optional 最佳实践

目录

一 Optional 是什么

二 Optional API介绍

三 Optional 最佳实践

3.1 不要直接返回 null,使用 Optional.empty();

3.2 正确使用 ifPresent()

3.3 少用 get(),多用orElse()和orElseGet()

3.4 少用of(),多用ofNullable()

四 Optional 常见用法


Optional 是什么

Optional 的作者 Brian Goetz 对这个 API 的说明:

Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors.

为了避免 null 带来的错误,我们提供了一个可以明确表示空值的有限的机制。

Optional是一个容器,用于放置可能为空的值,它可以合理而优雅的处理null

Optional API介绍

public static<T> Optional<T> empty();  // 返回一个Optional容器对象

public static <T> Optional<T> of(T value); // 创建一个Optional对象,如果 value 是 null,则抛出 NPE

public static <T> Optional<T> ofNullable(T value); // 创建一个Optional对象,但 value 为空时返回Optional.empty()

public T get(); // 返回Optional中包装的值,在判空之前,千万不要直接使用

public boolean isPresent(); // 判断Optional中是否有值,返回 boolean

public void ifPresent(Consumer<? super T> consumer); // 判断Optional中是否有值,有值则执行 consumer,否则什么都不干

public T orElse(T other); // 返回Optional中包装的值,但不同的是当取不到值时,返回你指定的 default

public T orElseGet(Supplier<? extends T> other); // 返回Optional中包装的值,取不到值时,返回你指定的 default

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier); // 返回Optional中包装的值,取不到值时抛出指定的异常

Optional 最佳实践

Optional 属于返回类型,通常在业务返回值或者远程调用中使用。

3.1 不要直接返回 null,使用 Optional.empty()

// 使用Optional.empty()之前
private PoiTabHintDTO getPoiTabHintFromTask(FutureTask<PoiTabHintDTO> task) {
    if (Objects.isNull(task)) {
        return null;
    }
    try {
        return ThreadPoolUtils.get(task, 4, TimeUnit.SECONDS);
    } catch (Exception e) {
        log.error("getRdcPoiTabHintFromTask", e);
        Cat.logMetricForCount("getRdcPoiTabHintFromTask");
        return null;
    }
}

// 使用Optional.empty() 
private Optional<PoiTabHintDTO> getPoiTabHintFromTask(FutureTask<Optional<PoiTabHintDTO>> task) {
    if (Objects.isNull(task)) {
        return Optional.empty();
    }
    try {
        return ThreadPoolUtils.get(task, 4, TimeUnit.SECONDS);
    } catch (Exception e) {
        log.error("getRdcPoiTabHintFromTask", e);
        Cat.logMetricForCount("getRdcPoiTabHintFromTask");
        return Optional.empty();
    }
}
// 需要显示的从optional容器里面获取对象,能减少NPE的产生。

3.2 正确使用 ifPresent()

// 使用 ifPresent()之前
if (getPoiTabHintFromTask(rdcPoiHintTask).isPresent()) {
    poiTabHintList.add(getPoiTabHintFromTask(rdcPoiHintTask).get());
}
// 使用 ifPresent()
getPoiTabHintFromTask(rdcPoiHintTask).ifPresent(poiTabHintList::add);

//性能没有提升,代码变得简洁。
3.3 少用 get(),多用orElse()和orElseGet()
// orElse()适用于入参是具体的值
public static ConfirmAuthorizationEnum getByCode(int code) {
    return Arrays.stream(ConfirmAuthorizationEnum.values())
        .filter(x -> code == x.getCode())
        .findFirst()
        .orElse(ConfirmAuthorizationEnum.UNINITIALIZED);
}
// orElseGet()适用于lamda表达式
private Optional<DeliveryReturnBillBO> getReturnBillFromList(
    List<DeliveryReturnBillBO> allDeliveryReturnBillList, String returnBillNo) {
    return Optional.ofNullable(allDeliveryReturnBillList.stream()
        .filter(deliveryReturnBillBO -> returnBillNo.equals(deliveryReturnBillBO.getReturnBillNo()))
        .findFirst()
        .orElseGet(() -> {
            log.error("未获取到退供单{}的详情信息", returnBillNo);
            Cat.logMetricForCount(DeliveryBill.RELATED_RETURN_BILL_IS_NULL);
            return null;
        }));
}
// 为啥少用 get(),需要结合判空使用,这和!=null其实没多大区别。

3.3 少用 get(),多用orElse()orElseGet()

// orElse()适用于入参是具体的值
public static ConfirmAuthorizationEnum getByCode(int code) {
    return Arrays.stream(ConfirmAuthorizationEnum.values())
        .filter(x -> code == x.getCode())
        .findFirst()
        .orElse(ConfirmAuthorizationEnum.UNINITIALIZED);
}
// orElseGet()适用于lamda表达式
private Optional<DeliveryReturnBillBO> getReturnBillFromList(
    List<DeliveryReturnBillBO> allDeliveryReturnBillList, String returnBillNo) {
    return Optional.ofNullable(allDeliveryReturnBillList.stream()
        .filter(deliveryReturnBillBO -> returnBillNo.equals(deliveryReturnBillBO.getReturnBillNo()))
        .findFirst()
        .orElseGet(() -> {
            log.error("未获取到退供单{}的详情信息", returnBillNo);
            Cat.logMetricForCount(DeliveryBill.RELATED_RETURN_BILL_IS_NULL);
            return null;
        }));
}
// 为啥少用 get(),需要结合判空使用,这和!=null其实没多大区别。

3.4 少用of(),多用ofNullable()

// 使用 of()场景
if (Objects.isNull(returnBillProcessBo)) {
    return Optional.empty();
}
return Optional.of(returnBillProcessBo);

// 使用 ofNullable()场景
return Optional.ofNullable(returnBillProcessBo);

 Optional 常见用法

package com.example.demo.domain;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 功能描述
 *
 * @since 2022-09-23
 */

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
    // 兴趣id列表
    private List<Long> favList;
    // 标签列表
    private List<Tag> tagList;

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Tag {
        private Long id;
    }

    /**
     * 获取兴趣id列表
     * @param user
     * @return
     */
    public List<Long> getFavList(User user) {
        return Optional.ofNullable(user)
                .map(User::getFavList)
                .map(Collection::stream)
                .orElse(Stream.empty())
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 获取标签id列表
     * @param user
     * @return
     */
    public List<Long> getTagIdList(User user) {
        return Optional.ofNullable(user)
                .map(User::getTagList)
                .map(Collection::stream)
                .orElse(Stream.empty())
                .map(Tag::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
                
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java8 Stream流的最佳实践包括以下几点: 1. 使用流的方法链来完成多个操作,可以使代码更加简洁和可读性更高。例如,可以使用filter()方法对流进行过滤,使用map()方法对流中的元素进行转换,使用collect()方法将流转换为集合等。 2. 避免修改流的源数据。流是一种惰性求值的操作,在对流进行操作时,不会修改原始数据,而是返回一个新的流。这样可以保持代码的幂等性和可维护性。 3. 使用并行流来并行处理大量的数据,以充分利用多核处理器的优势。但需要注意,并不是所有情况下都适合使用并行流,因为并行处理也会带来额外的开销。在选择是否使用并行流时,需要权衡数据量和计算复杂度。 4. 使用Collectors类提供的方法来收集流的结果。Collectors类提供了一系列的静态方法,可以方便地将流转换为List、Set、Map等常用的集合类型。 5. 使用Optional类来处理可能为空的结果。在对流进行操作时,有时可能会出现空指针异常的情况。使用Optional类可以避免出现空指针异常,并通过链式调用来处理可能为空的结果。 6. 尽量避免在流的操作过程中进行耗时的IO操作。流的操作是基于内存的,如果在流的操作过程中进行耗时的IO操作,可能会导致性能下降。 7. 使用流的短路操作来提高性能。例如,使用findFirst()方法来查找流中的第一个元素,如果找到符合条件的元素,就可以提前终止流的处理过程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值