【问题标题】:IllegalStateException when removing an object from a Collection从集合中删除对象时出现 IllegalStateException
【发布时间】:2017-06-23 13:31:57
【问题描述】:

我正在遍历 arrayList 并删除适用于某些条件的项目。

public static ArrayList<String> filteredArrayList(HashMap<String, Boolean> filters){

    ArrayList<String> filteredArrayList = new ArrayList<>();
    filteredArrayList = fullList();

    Iterator<String> i = filteredArrayList.iterator();
    while (i.hasNext()) {
        String s = i.next();

        if(!(filters.get("sometextStatus")) && (s.toLowerCase().trim().contains("sometext".trim().toLowerCase()))){
                i.remove();
        }
        if(!(filters.get("120Status")) && (s.toLowerCase().trim().contains("120".trim().toLowerCase()))){
                i.remove();
        }
    }
}

为什么第一个语句有效:

if(!(filters.get("sometextStatus")) && (s.toLowerCase().trim().contains("sometext".trim().toLowerCase()))){
    i.remove();
}

但是第二个失败了?

if(!(filters.get("120Status")) && (s.toLowerCase().trim().contains("120".trim().toLowerCase()))){
    i.remove();
}

我得到:

线程“主”java.lang.IllegalStateException 中的异常

第二个。

【问题讨论】:

  • 什么是“s”和“i”?我会帮助理解,例如了解类型,您可以显示循环(没有无用的行)
  • 我认为您在计算括号时提供的代码中缺少某些内容。
  • 要正确回答您的问题帖子minimal reproducible example
  • 要更新您的问题,请使用edit 选项。
  • 我们需要查看您的代码,还包含返回布尔值,并且在您知道其中没有空格的字符串上使用修剪没有任何意义。

标签: java arraylist contains


【解决方案1】:
public static ArrayList<String> filteredArrayList(HashMap<String, Boolean> filters){

    ArrayList<String> filteredArrayList = fullList(); //Note, that fullList method already creates and returns array, so you don't need to create it before calling this method.

    Iterator<String> i = filteredArrayList.iterator();
    while (i.hasNext()) {
        String s = i.next();

        if(!(filters.get("sometextStatus")) && (s.toLowerCase().trim().contains("sometext".trim().toLowerCase()))){
                i.remove();
                continue; //We removed current element, so next if check might potentially removed already removed element!
        }

        if(!(filters.get("120Status")) && (s.toLowerCase().trim().contains("120".trim().toLowerCase()))){
                i.remove();
                continue; //Maybe a programmer will decide to copy-paste if checks, so it is safer to do so with continue.
        }
    }
}

更新

调试后发现

Exception in thread "main" java.lang.NullPointerException
    at com.ca.training.jdk.loops.Main2.filteredArrayList(Main2.java:34)
    at com.ca.training.jdk.loops.Main2.main(Main2.java:14)

问题是如果

 filters.get("120Status")

返回NULL,这是可能的!?。所以添加一个空检查

Boolean status1 = filters.get("sometextStatus");
if((status1 != null && status1) && (s.toLowerCase().trim().contains("sometext".trim().toLowerCase()))) {
    i.remove();
}

关键字continue 使程序使用新的循环参数继续循环。所以当第一个if 语句为真时,我们不去第二个if 检查,而是继续循环执行下一个i 值。

建议

尽可能使用基类或接口而不是子类。

  public static ArrayList<String> filteredArrayList(Map<String, Boolean> filters){ //Note, map

  List<String> filteredArrayList = fullList(); //Note, list.

【讨论】:

  • 我们也可以使用else if
  • 我同意,在 remove 的情况下我们可以。如果 OP 想要将它们放入另一个集合而不是 remove 怎么办?然后最好使用 if 没有 else。同样,我同意,在这种情况下,else if 没问题!
  • 我仍然收到错误消息。你能解释一下 continue 的作用是什么吗?编辑:没关系,它确实适用于继续。这只是迭代循环还是什么?
  • @ConfidentKeyboard 我仍然收到错误消息。运行时或编译错误?
  • @YanKhonski 感谢您的更新!没想到!
【解决方案2】:

如果您使用的是 Java8,也许这会有所帮助。

当我们检查内容时,您不需要trim()该项目,而不是完全匹配。

如果你匹配的号码,你也不需要lowerCase()它。

删除项目的简单 lambda:

filteredArrayList.removeIf(s ->
                s.contains("123")
             || s.toLowerCase().contains("asd".toLowerCase())
             || s.toLowerCase().contains("something else".toLowerCase())
             || s.toLowerCase().contains("something else".toLowerCase())
        );

s 是列表中的项目,您可以随意调用它 - 是的,它是迭代器的项目。

【讨论】:

  • 嗯,这可以多次使用,比如删除其中包含不同字符串的项目吗?另外,在这种情况下 s 是什么?这还需要迭代器吗?
  • 谢谢!哪种方式更好?这种方法有什么好处吗?
  • 我不确定它的性能,我认为它更干净,更现代,更容易阅读,占用更少的空间,更少的混乱。可能在它下面做一些类似于你的事情。
  • 我认为原始方法可能更适合我的应用程序。我想将 if 语句分成几个部分,因为会有很多过滤,并且可能有很多过滤条件。不过谢谢,我不知道 .removeIf
  • 你的选择 ;) 它只是一个选项,我宁愿使用几个 lambdas,也不愿拥有一个包含数百个 if 语句的巨大方法。我刚刚提出了替代解决方案。
【解决方案3】:

我猜第一个 i.remove() 确实已经删除了该元素。当第二个检查也匹配时,第二个i.remove() 不再可能,而是抛出异常。无论何时拨打i.remove(),请使用continue;

continue 将跳转到循环的下一个元素。

但是如果您发布发生异常的确切代码行,这将更容易找出。

【讨论】:

  • 确切的代码行是:i.remove();在第二个 if 语句中。
  • 好的,那么你必须在 i.remove() 之后调用“继续”,或者使用 else if 而不是第二个 if 语句。
猜你喜欢
  • 2015-10-05
  • 2020-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多