【问题标题】:Writing a method with ArrayList of strings as parameters编写一个以字符串的 ArrayList 作为参数的方法
【发布时间】:2014-05-07 06:10:47
【问题描述】:

我正在尝试编写一个方法,该方法将字符串的 ArrayList 作为参数,并在每个长度为 4 的字符串前面放置一个由四个星号组成的字符串。

但是,在我的代码中,我在构建方法时遇到了错误。

这是我的标记长度类

import java.util.ArrayList;


public class Marklength {

    void marklength4(ArrayList <String> themarklength){
        for(String n : themarklength){
            if(n.length() ==4){
                themarklength.add("****");
            }
        }
        System.out.println(themarklength);
    }

}

以下是我的主要课程:

import java.util.ArrayList;


public class MarklengthTestDrive {
    public static void main(String[] args){

        ArrayList <String> words = new ArrayList<String>(); 

        words.add("Kane");
        words.add("Cane");
        words.add("Fame");
        words.add("Dame");
        words.add("Lame");  
        words.add("Same");

        Marklength ish = new Marklength();

        ish.marklength4(words);

    }
}

基本上在这种情况下,它应该运行,因此它添加了一个带有 "****" 字符串的数组列表,放在数组列表的每个前一个元素之前,因为字符串的长度都是 4。

顺便说一句

这包括添加另一个元素

我不确定我哪里出错了。可能在我的 for 循环中?

我收到以下错误:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at Marklength.marklength4(Marklength.java:7)
    at MarklengthTestDrive.main(MarklengthTestDrive.java:18)

非常感谢。帮助表示赞赏。

【问题讨论】:

  • 请同时发布您的错误。
  • 阅读List#add的javadoc。然后寻找它的重载方法。
  • 您正在尝试修改仅为该 foreach 循环创建的临时变量:stackoverflow.com/questions/85190/…, docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
  • 在使用 for ( : ) 迭代列表时,您不能更改列表。尝试使用 for (int i = 0; i
  • 您想在长度为 4 的字符串前面附加四个星号,还是想在字符串前面的列表中添加另一个元素?所以,如果你有["item"],你希望它看起来像["****item"],还是["****", "item"]

标签: java methods arraylist


【解决方案1】:

让我们想想这段代码,并假装你没有得到那个异常:

import java.util.ArrayList;


public class Marklength {

    void marklength4(ArrayList <String> themarklength){
        for(String n : themarklength){
            if(n.length() ==4){
                themarklength.add("****");
            }
        }
        System.out.println(themarklength);
    }
}

好的,如果您的列表只包含 item 会发生什么。

您点击了if(n.length() ==4){ 行,这是真的,因为您正在查看项目,所以您执行它的块。

接下来你点击themarklength.add("****");。现在,您的列表末尾有元素 ****

循环继续,您将获得列表中的下一项,恰好是您刚刚添加的一项,****

您点击的下一行是if(n.length() ==4){。这是真的,所以你执行它的块。 您转到themarklength.add("****"); 行,并将**** 添加到列表末尾。

我们在这里看到不好的模式吗?是的,是的。

Java 运行时环境也知道这是不好的,这就是为什么它防止一种叫做并发修改的东西。在您的情况下,这意味着您在迭代列表时无法修改列表,这就是 for 循环所做的。

我对你想要做什么的最好猜测是这样的:

import java.util.ArrayList;


public class Marklength {

    ArrayList<String> marklength4(ArrayList <String> themarklength){
        ArrayList<String> markedStrings = new ArrayList<String>(themarklength.size());
        for(String n : themarklength){
            if(n.length() ==4){
                markedStrings.add("****");
            }
            markedStrings.add(n);
        }
        System.out.println(themarklength);
        return markedStrings;
    }
}

然后:

import java.util.ArrayList;


public class MarklengthTestDrive {
    public static void main(String[] args){

        ArrayList <String> words = new ArrayList<String>(); 

        words.add("Kane");
        words.add("Cane");
        words.add("Fame");
        words.add("Dame");
        words.add("Lame");  
        words.add("Same");

        Marklength ish = new Marklength();

        words = ish.marklength4(words);

    }
}

【讨论】:

  • "Java 编译器也知道" - 不,它不知道 Concurrent Modification 是运行时异常,不是编译器错误,但语句的其余部分是正确的跨度>
  • @MadProgrammer 哦,非常正确,我的错。我会解决的。谢谢。
  • 好的,要获得 +1,您有什么建议可以解决? ;)
  • @MadProgrammer 我实际上并不确定他想要什么,我只是发表了一条评论,要求他澄清一下。根据他的问题,他可能希望["item"] 变成["****item"]["****","item"],甚至是[["****"],"item"](这是不可能的)。
  • 我会为此 +1。这是一个挑剔的问题,不会影响您的回答,但我可能会建议使用ArrayList&lt;String&gt; markedStrings = new ArrayList&lt;String&gt;(themarklength.size()),因为它可以提供更好的性能
【解决方案2】:

这...

if(n.length() ==4){
    themarklength.add("****");
}

只是试图将"****" 添加到列表的末尾。这会失败,因为for-each 循环使用的Iterator 不允许在底层List 被迭代时发生更改。

您可以先创建List 的副本...

List<String> values = new ArrayList<String>(themarklength);

或者将其转换为String的数组

String[] values = themarklength.toArray(new String[themarklength.size()]);

并使用这些作为迭代点...

for (String value : values) {

接下来,您需要能够在ArrayList 的特定点插入新元素。为此,您需要知道您正在使用的值的原始索引...

if (value.length() == 4) {
    int index = themarklength.indexOf(value);

然后在需要的位置添加一个新值……

    themarklength.add(index, "****");

这将在index 点添加"****",将所有其他条目向下推

更新

正如已经正确地向我指出的那样,themarklength.indexOf(value) 的使用不会考虑themarklength 列表包含两个相同值的元素的用例,这将返回错误的索引。

我也没有将性能作为提供可能解决方案的主要要求。

更新...

正如 JohnGarnder 和 AnthonyAccioly 所指出的,您可以使用 for-loop 而不是 for-each,这样您就可以省去 themarklength.indexOf(value)

这将消除重复值弄乱索引位置的风险并提高整体性能,因为您不需要创建第二个迭代器...

// This assumes you're using the ArrayList as the copy...
for (int index = 0; index < themarklength.size(); index++) {
    String value = themarklength.get(index);
    if (value.length() == 4) {
        themarklength.add(index, "****");
        index++;

但你使用哪个取决于你......

【讨论】:

  • 不确定不赞成票的来源,您的投票与赞成票相同(可能是后期编辑?)如果您使用 for 循环而不是 foreach 样式,则不需要额外的索引。
  • @JohnGardner 是的。您必须喜欢那些不发表评论就对问题和答案投反对票的人的勇气……人们应该如何学习或有机会提高帖子的质量:P
  • @JohnGardner 我当然不是为了投票,因为我帮助领先的问题提供了一个可能的答案;)
  • 是的,我知道我只是在指出投反对票有时很疯狂:)
  • @JohnGardner,我赞成,我是最初的反对者,但我去吃饭了。我最初投反对票的原因是indexOf(value) 策略被破坏了。在性能方面 - 每次找到一个元素时都需要额外的迭代 - 以及在正确性方面 - 如果您有两个相等的字符串,如果在第一个位置之前插入 **** 两次,这是错误的。为了使其工作,您必须跟踪最后一个索引并使用 indexOf(String str, int fromIndex) 变体,这仍然需要部分新的迭代。
【解决方案3】:

问题是在你的方法中,你并没有修改arraylist中的每个字符串,而只是在列表中添加了4颗星。所以正确的做法是,你需要修改arraylist的每个元素,用新的替换旧的字符串:

void marklength4(ArrayList<String> themarklength){
    int index = 0;
    for(String n : themarklength){
        if(n.length() ==4){
            n = "****" + n;
        }
        themarklength.set(index++, n);
    }
    System.out.println(themarklength);
}

如果这不是你想要的,但你想在数组列表中的每个元素之前添加一个新字符串“**”,那么你可以在ArrayList 中使用listIterator 方法来如果长度为 4,则在每个字符串之前添加新的附加元素。

    ListIterator<String> it = themarklength.listIterator();
    while(it.hasNext()) {
        String name = it.next();
        if(name.length() == 4) {
            it.previous();
            it.add("****");
            it.next();
        }
    }

不同之处在于:ListIterator 允许您在迭代列表时修改列表,也允许您在列表中后退。

【讨论】:

  • 是的,这也是我认为 OP 想要做的事情,但我相信他们想在每个匹配元素之前添加 "****",而不是前缀 - 可能是错误的,但这就是我现在的方式阅读它:P
【解决方案4】:

我会使用 ListIterator 而不是 for each,listiterator.add 可能完全符合您的要求。

public void marklength4(List<String> themarklength){
    final ListIterator<String> lit = 
        themarklength.listIterator(themarklength.size());
    boolean shouldInsert = false;   
    while(lit.hasPrevious()) {
        if (shouldInsert) {
            lit.add("****");
            lit.previous();
            shouldInsert = false;
        }
        final String n = lit.previous();
        shouldInsert = (n.length() == 4);
    }
    if (shouldInsert) {
        lit.add("****");
    }
}

Working example

【讨论】:

  • 我认为这可能会中断,虽然我喜欢这个想法,但它会在最后一个元素“之后”添加值,需要开始搞乱previousnext...:P
  • @MadProgrammer,实际上,之前只是意味着反向迭代。检查我的例子。
【解决方案5】:

哦,我记得过去美好时光中的这个可爱的错误。问题是您的 ArrayList 在要访问数组元素时尚未完全填充。想想看,你创建了对象,然后立即开始循环它。因此,当循环将要运行时,对象必须用值填充自己。

解决这个问题的简单方法是预先填充您的 ArrayList。

public class MarklengthTestDrive {
    public static void main(String[] args){

        ArrayList <String> words = new ArrayList<String>() {{ 

        words.add("Kane");
        words.add("Cane");
        words.add("Fame");
        words.add("Dame");
        words.add("Lame");  
        words.add("Same");
        }};
    }
}

请告诉我这是否能解决问题。您还可以使用 static 初始化程序。

【讨论】:

  • 所以我得到“不能引用在不同方法中定义的内部类中的非最终变量词。”
【解决方案6】:

制作临时arraylist,修改此列表并将其末尾的内容复制到原始列表中

    import java.util.ArrayList;

    public class MarkLength {
    void marklength4(ArrayList <String> themarklength){
        ArrayList<String> temp = new ArrayList<String>();
        for(String n : themarklength){
            if(n.length() ==4){
                temp.add(n);
                temp.add("****");
            }
        }
        themarklength.clear();
        themarklength.addAll(temp);
        System.out.println(themarklength);
    }
}

【讨论】:

    猜你喜欢
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多