当前位置: 首页 > 面试题库 >

Java 8收集器,如果只有一个值,则返回一个值

杜英叡
2023-03-14
问题内容

我对这种函数式编程和流技术有点陌生,但是我所知道的一点却非常有用!

我遇到过几次这种情况:

List<SomeProperty> distinctProperties = someList.stream()
    .map(obj -> obj.getSomeProperty())
    .distinct()
    .collect(Collectors.toList());

if (distinctProperties.size() == 1) {
    SomeProperty commonProperty = distinctProperties.get(0);
    // take some action knowing that all share this common property
}

我真正想要的是:

Optional<SomeProperty> universalCommonProperty = someList.stream()
    .map(obj -> obj.getSomeProperty())
    .distinct()
    .collect(Collectors.singleOrEmpty());

我认为,singleOrEmpty除了与结合使用外,该东西在其他情况下也可能有用distinct。当我成为超级n00b时,我花了很多时间重新发明Java
Collections
Framework,因为我不知道它在那里,所以我试图不重蹈覆辙。Java是否提供了执行此操作的好方法singleOrEmpty?我说错了吗?

谢谢!

编辑:这是distinct案例的一些示例数据。如果您忽略该map步骤:

Optional<SomeProperty> universalCommonProperty = someList.stream()
    .map(obj -> obj.getSomeProperty())
    .distinct()
    .collect(Collectors.singleOrEmpty());

[]     -> Optional.empty()
[1]    -> Optional.of(1)
[1, 1] -> Optional.of(1)
[2, 2] -> Optional.of(2)
[1, 2] -> Optional.empty()

当我搞砸我的类型或有旧代码时,我发现我需要这个。能够快速地说出“此集合的所有元素共享此属性,这真是太好了,因此现在我可以使用此共享属性采取一些措施。”
另一个示例是,当用户多重选择一些不同的元素,而您试图查看可以做的事情(如果有的话)对所有元素都有效。

EDIT2:对不起,如果我的例子有误导性。关键是 singleOrEmpty
。我通常会发现我放在distinct前面,但也可以很容易地成为filter其他类型的对象。

Optional<SomeProperty> loneSpecialItem = someList.stream()
    .filter(obj -> obj.isSpecial())
    .collect(Collectors.singleOrEmpty());

[special]           -> Optional.of(special)
[special, special]  -> Optional.empty()
[not]               -> Optional.empty()
[not, special]      -> Optional.of(special)
[not, special, not] -> Optional.of(special)

EDIT3:我想通过激励 singleOrEmpty 而不是 单独 要求它来搞砸。

Optional<Int> value = someList.stream().collect(Collectors.singleOrEmpty())
[]     -> Optional.empty()
[1]    -> Optional.of(1)
[1, 1] -> Optional.empty()

问题答案:

仅评估前两个元素的“ Hacky”解决方案:

    .limit(2)
    .map(Optional::ofNullable)
    .reduce(Optional.empty(),
        (a, b) -> a.isPresent() ^ b.isPresent() ? b : Optional.empty());

一些基本的解释:

单个元素 [1]->映射到[Optional(1)]-> reduce

"Empty XOR Present" yields Optional(1)

=可选(1)

两个元素 [1,2]->映射到[Optional(1),Optional(2)]-> reduce可以:

"Empty XOR Present" yields Optional(1)
"Optional(1) XOR Optional(2)" yields Optional.Empty

=可选。空

这是完整的测试用例:

public static <T> Optional<T> singleOrEmpty(Stream<T> stream) {
    return stream.limit(2)
        .map(Optional::ofNullable)
        .reduce(Optional.empty(),
             (a, b) -> a.isPresent() ^ b.isPresent() ? b : Optional.empty());
}

@Test
public void test() {
    testCase(Optional.empty());
    testCase(Optional.of(1), 1);
    testCase(Optional.empty(), 1, 1);
    testCase(Optional.empty(), 1, 1, 1);
}

private void testCase(Optional<Integer> expected, Integer... values) {
    Assert.assertEquals(expected, singleOrEmpty(Arrays.stream(values)));
}

对于贡献XOR想法和上述测试用例的Ned(OP)表示感谢!



 类似资料:
  • 我对函数式编程和流的东西有点陌生,但我所知道的一点非常有用! 我认为除了与结合使用之外,还可以在其他情况下使用。当我还是uber n00b的时候,我花了很多时间重新设计Java集合框架,因为我不知道它在那里,所以我试着不重复我的错误。Java是否提供了一种很好的方法来完成的事情?我说错了吗? 谢谢! 编辑:下面是一些案例的示例数据。如果忽略步骤:

  • 我的数据库中有两个表: 表1:购买物品 表1列出了购买的物品,表2每小时更新一次每件物品的当前价格。因此,从表2中可以清楚地看出,肉类最后一次交易是在2013年2月20日上午10点,而鱼类不是在同一天交易的,它是在2013年2月19日上午9点交易的,鸡肉是在2013年2月20日上午9点交易的。我想做的是,列出表1中的所有项目,并加入表2中各个项目的最后交易价格,如下所示: 这里应该应用什么类型的连

  • 我是流运营商的忠实粉丝。它不在标准库中,但我发现它非常有用。如果流只有一个值,它将在中返回该值。如果它没有值或有多个值,则返回。 我之前问了一个问题,@ThomasJungblut想出了这个很棒的实现: 唯一的问题是,你必须把它放在你的电话开始时 而不是按顺序结束 这使得它比其他流机制更难阅读。 作为流处理的新手,有人知道如何在一系列流转换的末尾设置一个短路的< code > single emp

  • 假设我有以下工作的lambda表达式: 我想在过滤器语句之前创建一个具有2个值的流。所以我想做一个映射,但仍然保留原始值。我想实现这样的事情: 这可能与Java8流?我已经看了收集(GroupingBy()),但仍然没有成功。

  • 问题内容: 我有这种简单的查询,它返回给定id的非空整数字段: 问题是,如果找不到ID,则结果集为空。我需要查询始终返回一个值,即使没有结果也是如此。 我有这个东西工作,但我不喜欢它,因为它运行相同子查询的2倍: 如果该行存在,则返回field1,否则返回0。有什么改进的方法吗? 谢谢! 编辑以下一些评论和答案 :是的,它必须在 单个查询语句中, 并且我不能使用count技巧,因为 我只需要返回1

  • 问题内容: 如果我有多个选择,例如: …如果第一个选择返回内容,我得到1个结果集。但是,如果运行第二个,我将得到两个结果集。第一个没有行,第二个没有行。 如果运行第二个选择,是否有办法仅返回第二个结果集? 谢谢! 问题答案: 您需要通过 在 运行选择 之前 检查是否会返回任何结果来阻止首次选择。 例如: