草庐IT

如果列表为空,Java lambda 返回 null,否则返回值的总和?

coder 2024-03-11 原文

如果我想汇总一个账户的当前余额列表,我可以这样做:

accountOverview.setCurrentBalance(account.stream().
                filter(a -> a.getCurrentBalance() != null).
                mapToLong(a -> a.getCurrentBalance()).
                sum());

但是这个表达式将返回 0,即使所有余额都为空。如果所有余额都为空,我希望它返回 null,如果有非空 0 余额,则返回 0,否则返回余额之和。

如何使用 lambda 表达式执行此操作?

非常感谢

最佳答案

一旦从流中过滤掉它们,就无法知道是否所有余额都是 null (除非检查 count() 返回的内容,否则您将无法使用该流,因为它是终端操作)。

对数据进行两次传递可能是直接的解决方案,我可能会首先采用:

boolean allNulls = account.stream().map(Account::getBalance).allMatch(Objects::isNull);

Long sum = allNulls ? null : account.stream().map(Account::getBalance).filter(Objects::nonNull).mapToLong(l -> l).sum();

您可以使用 reduce 的解决方案摆脱过滤步骤,尽管可读性可能不是最好的:

Long sum = account.stream()
                  .reduce(null, (l1, l2) -> l1 == null ? l2 :
                                                         l2 == null ? l1 : Long.valueOf(l1 + l2));

注意 Long.valueOf称呼。这是为了避免条件表达式的类型是long。 ,因此在某些边缘情况下是 NPE。


另一种解决方案是使用 Optional应用程序接口(interface)。首先,创建一个 Stream<Optional<Long>>从余额值中减去它们:

Optional<Long> opt = account.stream()
                            .map(Account::getBalance)
                            .flatMap(l -> Stream.of(Optional.ofNullable(l)))
                            .reduce(Optional.empty(),
                                    (o1, o2) -> o1.isPresent() ? o1.map(l -> l + o2.orElse(0L)) : o2);

这会给你一个 Optional<Long>如果所有值都是 null,那将是空的,否则它将为您提供非空值的总和。

或者您可能想为此创建一个自定义收集器:

class SumIntoOptional {

    private boolean allNull = true;
    private long sum = 0L;

    public SumIntoOptional() {}

    public void add(Long value) {
        if(value != null) {
            allNull = false;
            sum += value;
        }
    }

    public void merge(SumIntoOptional other) {
        if(!other.allNull) {
            allNull = false;
            sum += other.sum;
        }
    }

    public OptionalLong getSum() {
        return allNull ? OptionalLong.empty() : OptionalLong.of(sum);
    }
}

然后:

OptionalLong opt = account.stream().map(Account::getBalance).collect(SumIntoOptional::new, SumIntoOptional::add, SumIntoOptional::merge).getSum();


如您所见,有多种方法可以实现这一点,所以我的建议是:首先选择最易读的。如果您的解决方案出现性能问题,请检查它是否可以改进(通过并行转换流或使用其他替代方案)。但是测量,不要猜测。

关于如果列表为空,Java lambda 返回 null,否则返回值的总和?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31785082/

有关如果列表为空,Java lambda 返回 null,否则返回值的总和?的更多相关文章

  1. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby - RVM 使用列表[0] - 2

    是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  6. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  7. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  8. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  9. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  10. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

随机推荐