【问题标题】:Java lambda: catch exception on a duplicate key mappingJava lambda:在重复键映射上捕获异常
【发布时间】:2017-01-27 22:51:27
【问题描述】:

我有一个Map<Person, Long> personToSalary,我想将其映射到另一个Map<String, Long> lastnameToSalary

现在,这可能会导致两个通常不相等的 Person 对象将具有相等的 lastname 属性,这将导致重复键插入到新映射中。这没关系,只要我能捕捉到这个异常,并抛出我自己的异常。但不知道该怎么做。

这里是代码。

   Map<Person, Long> personToSalaray = getMappings();

   // lastname to salary
   Map<String, Long> personToSalary.entrySet().stream()
            .collect(toMap(
                    e -> e.getKey().getLastname(),
                    e -> e.getValue()));

虽然这可行,但它可能会在重复键插入(相同的姓氏)时引发异常。怎么抓?我无法在 toMap 中声明 try-catch。

【问题讨论】:

    标签: java lambda exception-handling java-8


    【解决方案1】:

    根据Collectors.map()的Javadocs:

    如果映射的键包含重复项(根据Object.equals(Object)),则在执行收集操作时会抛出IllegalStateException。如果映射的键可能有重复,请改用toMap(Function, Function, BinaryOperator)

    因此,解决方案不应捕获异常,而是使用专门设计用于处理重复项的其他 toMap 重载。该方法的文档提供了一个接近您的场景的示例:

    有多种方法可以处理映射到同一个键的多个元素之间的冲突。 toMap 的其他形式只是使用无条件抛出的合并函数,但您可以轻松编写更灵活的合并策略。例如,如果您有一个 Person 流,并且您想生成一个“电话簿”映射名称到地址,但可能有两个人具有相同的名称,您可以执行以下操作来优雅地处理这些冲突,并生成一个映射名称到串联地址列表的 Map:

    Map<String, String> phoneBook
         people.stream().collect(toMap(Person::getName,
                                       Person::getAddress,
                                       (s, a) -> s + ", " + a));
    

    【讨论】:

      【解决方案2】:

      使用https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-

      Map<String, Long> personToSalary.entrySet().stream()
                  .collect(toMap(
                          e -> e.getKey().getLastname(),
                          e -> e.getValue(),
                          (a, b) -> a // just choose one of the duplicates, or you can put more logic to decide which one you need
      ));
      

      【讨论】:

      • 所以 BinaryOperator 将对正在创建的新地图中的键进行操作,即在我的情况下是字符串姓氏?
      • @wesleyy 它将对值而不是键进行操作,即 Long 值。
      • @AR.3 但前提是密钥相同,对吧?所以 (a,b) 是 Long 值,但我可以在这里抛出一个异常,说“相同的姓氏出现了两次”?
      • @wesleyy 是的 a 和 b 是相同键的长值。我不确定你是否可以在 lambda 中抛出异常,但如果需要捕获和抛出异常,为什么不简单地使用第一个 toMap。如前所述,如果出现重复键,它会抛出 IllegalStateException。
      猜你喜欢
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      相关资源
      最近更新 更多