如何在 Java 上使用 Optional 在 ifPresent 中进行多项操作?

How to make multiple operation in ifPresent with Optional on Java?

我所做的只是用户可以进行交易,但首先我需要检查账户余额(usdt 和比特币账户)。简单的事情是,对于买入我只检查 usdt 账户余额而对于卖出我只检查加密货币余额但问题是这些账户也可以为空,这就是为什么我需要使用 Optional.

这是我的比较代码;

private boolean isBalanceAvailableForTrade(TradeRequestDto requestDto, List<Account> accountList) {
        Optional<Account> dollarAccount = accountList.stream()
                .filter(account -> account.getAccountCurrencyType().equals(Currency.USDT.toString()))
                .findFirst();
        Optional<Account> cryptoAccount = accountList.stream()
                .filter(account -> account.getAccountCurrencyType().equals(requestDto.getCurreny()))
                .findFirst();

        if (requestDto.getOperationType().equalsIgnoreCase(BUY)) {
            if (dollarAccount.get().getAmount().compareTo(BigDecimal.valueOf(0)) > 0) {
                return true;
            }
            //TODO throw no available amount exception etc.
            return false;
        }
        if (requestDto.getOperationType().equalsIgnoreCase(SELL)) {
            if(cryptoAccount.get().getAmount().compareTo(BigDecimal.valueOf(0)) > 0) {
                return true;
            }
            //TODO throw no available amount exception etc.
            return false;
        }
        return false;
    }

我的问题实际上是我没有检查上面的帐户是否为空,行

`if (dollarAccount.get().getAmount().compareTo(BigDecimal.valueOf(0)) > 0)` may throw *NullPointerException*.

我需要这样的东西:

dollarAccount.ifPresent(()-> {then do multiple line of code/operation} ).orElseThrow(some exception)

我认为我非常接近解决方案,但我无法弄清楚如何实现可选的多重检查(余额检查和空检查)。我应该如何正确重构这段代码?

旁注:我不确定以下帐户检查是否也是最佳做法,如果您能提出建议,我们非常欢迎

Optional<Account> dollarAccount = accountList.stream()
                    .filter(account -> account.getAccountCurrencyType().equals(Currency.USDT.toString()))
                    .findFirst();

.orElseThrow() returns 包含的值,因此您只需使用它而不是 .get():

dollarAccount.orElseThrow(() -> new Exception()).getAmount().compareTo(BigDecimal.valueOf(0)) > 0

也许只是把它分开,这样它就不会太长(并且可能会删除 if):

Account account = dollarAccount.orElseThrow(() -> new Exception());
return account.getAmount().compareTo(BigDecimal.valueOf(0)) > 0;

您应该避免在 Optional 上使用 get。您可以使用 orElseThrow 解压一个可选的,如下所示:

Account account = dollarAccount.orElseThrow(() -> new NotFoundException("Dollar account not found!));

这将 return 一个 Account 或如果可选为空则抛出异常。

附注:

您的流看起来正确,如果 accountList 为空或者 filter 找不到任何帐户,它将 return 一个空的可选。否则,过滤将在找到第一个帐户时停止。

我建议您将查找帐户和获取其余额的逻辑提取到一个单独的方法中。它将使代码更加连贯和简洁。

方法getAmount() returns一个BigDecimal并且不需要处理[=29=里面的Optional ]isBalanceAvailableForTrade()。

因此,如果找不到给定货币的帐户,您可以抛出异常,最好在 orElseThrow() 中使用 getAmount() 方法,而不是在调用链下游打扰可选对象。

problem is actually I am not checking if the accounts are null

为避免 NPE,向流中添加一个过滤器就足够了(查看 getAmount() 方法),并且它必须是管道中的第一个操作.

private boolean isBalanceAvailableForTrade(TradeRequestDto requestDto, List<Account> accountList) {
        BigDecimal dollarAccAmount = getAmount(accountList, Currency.USDT.toString());
        BigDecimal cryptoAccAmount = getAmount(accountList, requestDto.getCurreny());

        if (requestDto.getOperationType().equalsIgnoreCase(BUY)) {
            if (dollarAccAmount.compareTo(BigDecimal.ZERO) > 0) {
                return true;
            }
            throw new NoAvailableAmountException();
        }
        if (requestDto.getOperationType().equalsIgnoreCase(SELL)) {
            if (cryptoAccAmount.compareTo(BigDecimal.ZERO) > 0) {
                return true;
            }
            throw new NoAvailableAmountException();
        }
        return false;
    }
    private BigDecimal getAmount(List<Account> accountList, String currency) {
        return accountList.stream()
                .filter(account -> account != null)
                .filter(account -> account.getAccountCurrencyType().equals(currency))
                .findFirst()
                .map(Account::getAmount)
                .orElseThrow(() -> new RuntimeException("unable to find an Account for currency " + currency));
    }

I need something like :

dollarAccount.ifPresent(()-> {then do multiple line of code/operation} ).orElseThrow(some exception)

为此 Optional class 提供了方法 filter(), map(), flatMap()。从 Java 9 开始,我们有 stream() 可以创建空流或具有单个元素的流。这允许您根据需要在可选对象上链接映射和过滤操作,或者将可选对象转换为流。

请注意,在方法 getAmount() 中调用了操作 map(accountList::getAmount) 不是 在流的元素上,而是在 Optional 对象上,由终端操作 findFirst().

返回

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html#method.summary