对私人列表的迭代问题

时间:2013-06-27 18:39:07

标签: java list exception-handling iteration private

我有一个SomeClass的课程,里面有一个List<String> someList。我需要让其他类迭代列表元素,但不要让它们更改列表或列表元素。测试以下代码:

public class SomeClass {
    static private List<String> someList;

    public static List<String> getSomeList() {
        return someList;
    }
    SomeClass(Array<String> someArray){
        someList=Collections.unmodifiableList(Arrays.asList(someArray));
    }

}
public class DoSomething {
    for (String s : SomeClass.getSomeList()){
    s+="Gotcha";
    }
}

将显示s将仅在for循环中更改 - 一旦完成,getSomeList()将返回旧的旧列表,因此不会保存任何更改。同时尝试调用getSomeList()。add(“someString”)将导致异常:UnsupportedOperationException。 请解释(对于经验丰富的C编码员)这种行为背后的逻辑以及如何捕获该异常?

5 个答案:

答案 0 :(得分:2)

对于列表,使用Collections.unmodifiableList()返回外部无法修改的列表(即,您仍然可以修改SomeClass中的列表。)

public List<String> getInternalList() {
  return Collections.unmodifiableList(someList);
}

对于String,返回是安全的,因为String是immutable class

答案 1 :(得分:2)

String的+=运算符实际上创建了一个String的新实例,而不是修改原始的字符串对象。换句话说,以下两行代码是等效的:

s += "Gotcha"
s = new String(s + "Gotcha");

示例

以下是与您的doSomeThing

类似的示例
public class st {
  public static void main(String[] args) {
    String hello = "hello";
    String helloReference = hello; // making helloReference and hello refer to same object.
    helloReference += " world"; // perform +=
    System.out.format("`hello` = %s, `helloReference` = %s\n",
        hello, helloReference);
  }
}

及其输出如下,表明hello引用的对象不受+=执行的helloReference运算符的影响:

hello = `hello`, helloReference = `hello world`

在其他世界中,在+ =运算符之前:

    hello            helloReference
      |                     |
   -------------------------------
   |        "hello"              |
   -------------------------------

在+ =运算符之后,它将创建一个新实例并修改helloReference引用的对象:

    hello            helloReference
      |                     |             --------------------
      |                     --------------|   "hello world"  |
   -------------------------------        --------------------
   |        "hello"              |
   -------------------------------

所以你的代码是安全的,doSomeThing中执行的操作会影响你的SomeClass引用的对象:

public class DoSomething {
  for (String s : SomeClass.getSomeList()){
    // this create an new string instance to s
    s+="Gotcha"; 
  }
}

答案 2 :(得分:2)

  

一旦完成,getSomeList()将返回好的旧列表,所以没有   保存更改。

因为,Stringimmutable所以更改未反映在最终列表中。使用StringBuilderStringBuffer代替String作为元素列表。

  

同时尝试调用getSomeList()。add(“someString”)将导致   exception:UnsupportedOperationException。

因为,Arrays.asList(someArray)返回Arrays.ArrayList,这是Arrays类中定义的嵌套类,如下所示:

private static class ArrayList<E> extends AbstractList<E>
         implements RandomAccess, java.io.Serializable

此课程正在扩展AbstractList,而AbstractCollection则会延伸add(E e)。嵌套类ArrayList未覆盖AbstractList的{​​{3}}方法。因此,当您在此add()上致电List时,它会调用AbstractCollection public boolean add(E e) { throw new UnsupportedOperationException(); } 方法,该方法在其中定义如下:

add("something")

这就是您在致电{{1}}时获得add(E e)的原因。

答案 3 :(得分:1)

字符串是不可变的对象,因此您无法像这样更改它们。

其次,您无法在类体中执行代码。 DoSomething类应该有一个方法来执行该操作:

public class DoSomething {

    public static void doSomething() {
         //code            
    }
}

答案 4 :(得分:0)

来自javadoc, List stooges = Arrays.asList(“Larry”,“Moe”,“Curly”),它将为您提供返回由指定数组支持的固定大小列表。 因此,即使代码中没有以下内容,对此列表的任何修改都将导致java.lang.UnsupportedOperationException Collections.unmodifiableList(Arrays.asList(的someArray));