【问题标题】:How to dynamically prune Java List when Iterator does not support remove()?当 Iterator 不支持 remove() 时如何动态修剪 Java List?
【发布时间】:2012-11-21 21:23:32
【问题描述】:

我有以下代码:

Widget[] widgetArray = widgetService.getAllWidgets();
List<Widget> widgets = Arrays.asList(widgetArray);

// Prune out any Widgets named "Melvin".
Iterator<Widget> iter = widgets.iterator();
while(iter.hasNext()) {
    Widget w = iter.next();

    if("Melvin".equals(w.getName()))
        iter.remove();
}

当我运行此代码时,我得到一个运行时java.lang.UnsupportedOperationExceptionError,其中包含null 的模糊异常消息,该消息被抛出iter.remove() 行。好像有些JavaIterators不支持remove方法,会抛出这个异常。

我无法将 widgetService.getAllWidgets() 方法更改为返回 List&lt;Widget&gt; 并坚持使用 Widget[] 数组返回值。

所以我问:我可以做些什么来循环我的 widgets 数组并动态删除名为“Melvin”的数组?

【问题讨论】:

    标签: java list iterator


    【解决方案1】:

    如果您负担得起,只需制作列表的可变副本即可。替换

    List<Widget> widgets = Arrays.asList(widgetArray);
    

    List<Widget> widgets = new ArrayList<Widget>(Arrays.asList(widgetArray));
    

    【讨论】:

      【解决方案2】:

      只是推迟删除,直到迭代器完成:

      Widget[] widgetArray = widgetService.getAllWidgets();
      List<Widget> widgets = Arrays.asList(widgetArray);
      
      // Prune out any Widgets named "Melvin".
      List<Widget> toRemove = new ArrayList<Widget>();
      Iterator<Widget> iter = widgets.iterator();
      while(iter.hasNext()) {
          Widget w = iter.next();
      
          if("Melvin".equals(w.getName()))
              toRemove.add(w);
      }
      widgets.removeAll(toRemove);
      

      或者,只需使用逆逻辑从符合条件的小部件构建列表:

      List<Widget> widgets = new ArrayList<Widget>();
      // Add all Widgets not named "Melvin"
      for (Widget w : widgetService.getAllWidgets()) {
          if(!"Melvin".equals(w.getName()))
              widgets.add(w);
      }
      

      【讨论】:

      • 感谢@Ted Hopp (+1) - 我也想到了这一点(“删除”二级列表的概念),我想我很难相信 Java 没有没有更优雅的烤...
      • widgets 列表是一个固定大小的“指定数组的列表视图”(参见 JavaDoc)并且不能删除条目,因为您不能从数组中删除条目。即使widgets.removeAll(...) 也应该因为同样的原因而失败(没有测试它)。所以要走的路是遵循 Guido Simone 的回答(将所有内容复制到新的 ArrayList 然后修剪),或者您的第二个解决方案(复制过滤)。
      • 是的,我可以确认widgets.removeAll(...) 因同样的原因而失败。实施@Guido Simone 的解决方案...
      【解决方案3】:

      asList() 列表仍由数组支持。

      您可能希望遍历数组的每个元素并将其添加到一个全新的列表中。这需要两个循环。

      或者更好的是,比较字符串值,然后添加到列表中。这样,您就有了一个循环和一个全新的列表。

      【讨论】:

      • 看到第一个答案太晚了。和上面差不多。
      【解决方案4】:

      使用guava,您可以摆脱所有这些代码,让一个快速、经过良好测试的库为您处理。

      Collection<Widget> noMelvins = Collections2.filter( Arrays.asList(widgetArray), new Predicate<Widget>() {
          @Override public boolean apply( final Widget arg) {
              return !"Melvin".equals(arg.getName());
          }
      });
      

      【讨论】:

      • 不需要向项目添加新库
      • 对建议明确针对这种情况制作的工具的反对意见?奇怪的判断。谁能说 guava 还没有在项目中,或者他没有在项目的其他 25 个地方做类似的事情?许多其他观众可能会在这个答案中找到价值。在包中添加另一个工具没有错。
      • 虽然没有采纳你的建议,还是同意了(+1)
      • Apache Commons 具有与CollectionUtils.filter() 非常相似的实用程序
      猜你喜欢
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-25
      • 2016-11-17
      • 2019-04-18
      • 2017-09-16
      • 2014-03-11
      相关资源
      最近更新 更多