使用 java 8 Streams 从 DTO 中的数组列表中删除元素

Removing element from an array list within a DTO using java 8 Streams

提问人:Shahbaz Khan 提问时间:8/4/2018 最后编辑:Stefan ZobelShahbaz Khan 更新时间:8/6/2018 访问量:3548

问:

我有 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 终端操作来完成,但是是否有更好的方法可以做到这一点或其他人遵循的任何最佳实践。

谢谢

爪哇岛 爪哇-8 java-stream DTO 可变

评论


答:

1赞 Thiyagu 8/4/2018 #1

这里没有必要使用流。只需使用 Collection.removeIf

来自 javadoc(强调我的)

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

因此,您可以编写

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

如果你真的想使用流,那么从你离开的地方,你可以使用一个,并将传递过滤器的元素收集为一个列表。filterSomeOtherDataType

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

但是在此之后,您要么必须

  1. 使用上述 ()1SomeDTOfilterdListnew SomeDTO(someDTO.getAttrOne(), someDTO.getAttrTwo(), filterdList)

  2. 将现有的listAttrfilterdList (someDTO.setListAttr(filterdList))

1 我想你的意思是第二个实例变量的名称是 。attrTwo

4赞 davidxxx 8/4/2018 #2

事实上,你有两种方法:

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

  • 从实际列表中删除元素

第二种方式可能是您需要的,原因有很多,例如:

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

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

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

1 路)重新分配给新对象

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

2 way) 在当前对象中过滤

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
                      }
                );

评论

0赞 Shahbaz Khan 8/4/2018
我上面给出的代码只是一个示例代码。属性 List<SomeOtherDataType> 实际上在 SomeDTO 中并不直接可用,还有许多其他属性,而这些属性又具有 list 作为子。因此,要获取 SomeOtherDataType,我无论如何都必须执行一个流并到达那里,因此,如果我必须设置为过滤列表,我必须再次使用流并访问 SomeOtherDataType,然后按照我们的建议调用 setter。这样做是好的做法吗?因为我们穿越了两次溪流。
0赞 davidxxx 8/4/2018
这不是一个坏做法,但正如我的回答中所述,它可能有一些副作用或局限性。虽然我不太确定流是不可避免的。也许你应该编辑你的代码。
0赞 davidxxx 8/4/2018
@Shahbaz汗,如果它能帮助你:)