【问题标题】:Java 8: Stream a list and map to another list based on different filtersJava 8:流式传输列表并根据不同的过滤器映射到另一个列表
【发布时间】:2018-05-27 05:12:42
【问题描述】:

我有以下 代码:

public boolean foo(List<JSONObject> source, String bar, String baz) {
    List<String> myList = newArrayList();

    source.forEach(json -> {
        if (!(json.get(bar) instanceof JSONObject)) {
            myList.add(json.get(bar).toString());
        } else {
            myList.add(json.getJSONObject(attribute).get("key").toString());
        }
    });

    /**
     * do something with myList and baz
     */
}

我只是想知道是否有办法使用过滤器来内联 if-else 条件。

类似的东西:

List<String> myList = source.stream()
                .filter(json -> !(json.get(bar) instanceof JSONObject))
                .map(item -> item.get(attribute).toString())
                .collect(Collectors.toList());

如果我采用上述方法,我将错过本应为“其他”的情况。如何使用更多java-8 方式实现我想要的?

提前致谢!

【问题讨论】:

  • 您可以将您的if-else 移动到地图操作中,但它会变得不可读。 Java8 并不总是最好的方法,为什么不使用简单的旧迭代方式?

标签: java lambda collections java-8 java-stream


【解决方案1】:

这样的事情呢?

  List<String> myList = source.stream()
      .map(json -> !(json.get(bar) instanceof JSONObject) ? 
            json.get(bar).toString() : 
            json.getJSONObject(attribute).get("key").toString())
      .collect(Collectors.toList());

未经测试,但你明白了。

【讨论】:

    【解决方案2】:

    我看到的唯一方法是将条件放入 map 调用中。如果您使用filter,您将丢失“else”部分。

    List<String> myList = source.stream()
                .map(item -> {
                      if (!(item.get(bar) instanceof JSONObject)) {
                          return item.get(bar).toString();
                      } else {
                          return item.getJSONObject(attribute).get("key").toString();
                      }
                })
                .collect(Collectors.toList());
    

    或者,正如 Holger 在评论中建议的那样,使用三元条件运算符:

    List<String> myList = source.stream()
                .map(i -> (i.get(bar) instanceof JSONObject ? i.getJSONObject(attribute).get("key") : i.get(bar)).toString())
                .collect(Collectors.toList());
    

    【讨论】:

    • 为什么首先使用流,这是 OP 应该问自己的问题
    • @Eugene true,但它确实删除了 List 的显式创建并向其添加元素。
    • @Eran 这在某种程度上使情况变得更糟,没有办法将预期的大小传递给Collectors.toList(),而你可以使用 OP 的方法。顺便说一句,我讨论的不是你的答案,而是一般的方法
    • @Eran partitioningBy 然后根据分区结果将结果映射到列表中呢?!
    • @Eugene:如果你担心列表的初始容量,可以使用Arrays.asList( … stream op … .toArray(ElementType[]::new) )获取一个没有容量增加操作的列表(如果流可以预测大小)。但这很少是一个问题(或考虑,正如您注意到的 OP 的原始代码也没有尝试为列表指定初始容量)......
    【解决方案3】:

    您可以使用函数partitioningBy 接受Predicate 并返回Map&lt;Boolean, List&lt;T&gt;&gt;true 键包含谓词的正确值,false 键包含其他值。

    所以你可以像这样重写你的代码:

    Map<Boolean, List<String>> partition = source.stream()
                .collect(Collectors.partitionBy(json -> !(json.get(bar) instanceof JSONObject));
    

    在这种情况下,不需要使用过滤功能。

    List<String> valuesWhenTrue = partition.get(Boolean.TRUE).stream().map(item -> item.get(attribute).toString()).collect(Collectors.toList());   
    
    List<String> valuesWhenFalse = partition.get(Boolean.FALSE).stream().map(json.getJSONObject(attribute).get("key").toString()).collect(Collectors.toList());
    

    【讨论】:

      【解决方案4】:

      如何将 if-else 提取到私有函数中

      private String obtainAttribute(JSONObject json){
        if (!(json.get(bar) instanceof JSONObject)) {
          return json.get(bar).toString();
        }
          return json.getJSONObject(attribute).get("key").toString();
      }
      

      并在您的 lambda 表达式中调用它。

          List<String> myList = source.stream()
          .map(item -> obtainAttribute(item))
          .collect(Collectors.toList());
      

      【讨论】:

        猜你喜欢
        • 2017-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-27
        • 2017-09-22
        相关资源
        最近更新 更多