【问题标题】:Removing element from an array list within a DTO using java 8 Streams使用java 8 Streams从DTO中的数组列表中删除元素
【发布时间】:2018-08-04 06:25:17
【问题描述】:

我有 DTO,其中包含几个属性类型为 ArrayList

  1. 我想将此 DTO 作为参数。
  2. 然后用ArrayList获取属性。
  3. 然后基于一些谓词我想从ArrayList 中删除一些元素
  4. 最终返回修改后的 DTO

    public class SomeDTO{
    
    private String attrOne;
    private String attrTwo;
    private List<SomeOtherDataType> listAttr;
    // getters 
    // setter
    ...
    
    
    }
    
    // This is the method where I want to modify the DTO
    private void modifyDTO(SomeDTO someDTO){
    
     someDTO.getlistAttr()
       .stream()
       /// need help here, how to remove some element from list 
       /// based on some condition.
       /// note the changes in the list should be reflected in DTO 
    
    }
    

    这可以通过简单地执行 forEach 终端操作来完成,但有没有更好的方法或其他人遵循的任何最佳实践。

谢谢

【问题讨论】:

    标签: java java-8 java-stream dto mutable


    【解决方案1】:

    其实你有两种方法:

    • 收集包含要保留的元素的新列表并将其分配给字段

    • 从实际列表中移除元素

    出于多种原因,您可能需要第二种方式:

    • 通常对于List 字段,您不想创建新列表来更改其状态。您只想对引用不可变对象的字段进行此操作。

    • 如果某些对象在List 字段上保留引用,这些对象将引用旧对象。这是不可取的,并且会产生难以理解的副作用问题。

    • 创建整个过滤对象可能会在 CPU/内存方面产生成本,而从现有 List 中删除对象很可能更有效。

    一种方式)重新分配给一个新对象

     List<SomeOtherDataType> listAttr =
     someDTO.getlistAttr()
            .stream()
            .filter(o -> conditionToKeep)
            .collect(Collectors.toList());
    someDTO.setListAttr(listAttr);
    

    2方式)在当前对象中过滤

    someDTO.getlistAttr().removeIf(o -> conditionToRemove);
    

    编辑关于 OP 的评论

    即使过滤掉元素的条件需要挖掘SomeOtherDataType对象和组成它的元素,流仍然不是必需的。
    一个花哨的代码来说明这一点:

    someDTO.getlistAttr()
           .removeIf(o -> {
                            Bar bar = o.getFoo().getBar();
                            if (bar != null){
                                List<FooBar> fooBars = bar.getList(); 
                                if (fooBars.contains(...)){
                                     return true; // I remove in this case
                                }
                            }
                            return false; // in any other case I keep
                          }
                    );
    

    【讨论】:

    • 我上面给出的代码只是一个示例代码。属性 List 实际上在 SomeDTO 中并不直接可用,还有许多其他属性,而这些属性又具有列表作为儿子。所以要获得 SomeOtherDataType 我无论如何都必须做一个流并到达那里,所以如果我必须设置为过滤列表,我必须再次使用流并到达 SomeOtherDataType 然后按照我们的建议调用 setter。这样做是个好习惯吗?因为我们要遍历流两次。
    • 这不是一个坏习惯,但它可能会产生一些副作用或限制,如我的回答中所述。虽然我不太确定流是不可避免的。也许你应该编辑你的代码。
    • @Shahbaz Khan 如果它可以帮助你,那就太好了:)
    【解决方案2】:

    这里不需要使用流。你可以简单地使用Collection.removeIf

    来自 javadoc(重点是我的)

    删除此集合中满足给定谓词的所有元素。迭代过程中或谓词引发的错误或运行时异常将转发给调用者。

    因此,你可以写

    someDTO.getlistAttr().removeIf((someOtherDataType) -> /*Your logic here*/)
    

    如果你真的想使用 Streams,那么从你离开的地方,你可以使用 filter 并收集作为列表通过过滤器的 SomeOtherDataType 元素。

    List<SomeOtherDataType> filterdList =  someDTO.getlistAttr()
       .stream()
       .filter(someOtherDataType -> /* your logic */)
       .collect(Collectors.toList())
    

    但在此之后,您要么必须

    1. 使用上述filterdList (new SomeDTO(someDTO.getAttrOne(), someDTO.getAttrTwo(), filterdList))创建一个新的SomeDTO1

    2. 将现有的listAttr 设置为filterdList (someDTO.setListAttr(filterdList))

    1 我认为您的意思是第二个实例变量的名称是attrTwo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-12
      • 2018-06-01
      • 2015-09-14
      • 2018-02-22
      • 2022-01-13
      • 2012-03-30
      相关资源
      最近更新 更多