从中创建新的ArrayList时如何修改Collections.unmodifiableList(Java 8 SE)?

时间:2018-07-09 19:53:11

标签: java collections unmodifiable

我有一个getter,它返回一个不可修改的列表,例如:

public List<Product> getProductList() {
    if (productList == null)
        return new ArrayList<>();
    return Collections.unmodifiableList(productList);
}

我这样称呼这个吸气剂:

List<Product> productList = new ArrayList<>(report.getProductList());

然后我将此列表传递给另一个修改列表的方法,

for (Product product : productList) {
    product.addToAdvisoryList(advisory);
}

其中addToAdvisoryList(咨询顾问)为:

public void addToAdvisoryList(Advisory advisory) {
    if (advisoryList == null) {
        setAdvisoryList(Collections.singletonList(advisory));
    } else if (!isContainedAdvisory(advisoryList, advisory)) {
        List<Advisory> newAdvisoryList = new ArrayList<>(advisoryList);
        newAdvisoryList.add(advisory);
        setAdvisoryList(newAdvisoryList);
    }
}

运行这些代码后,原始产品列表将被修改。 有人可以解释到底发生了什么吗?以及如何避免修改不可修改的列表?

2 个答案:

答案 0 :(得分:0)

在您提供的代码中,原始(不可修改)列表作为参数传递给java.util.ArrayList(可修改列表)的构造函数。

List<Advisory> newAdvisoryList = new ArrayList<>(advisoryList);

此构造函数使用其迭代器返回的顺序(请参见documentation),以提供的Collection的所有项目创建一个新列表。

同样的事情发生在产品列表上:

List<Product> productList = new ArrayList<>(report.getProductList());

这使得首先返回不可修改的列表变得多余。

换句话说,您不是在修改不可修改的列表。您将使用不可修改(不可变)列表中的元素创建可修改的新列表,然后修改(可变)列表。

有关不可变列表的信息,请参见Java文档中的here。尝试修改不可变列表时,您会得到UnsupportedOperationException

编辑

回答有关吸气剂的问题:

“获取器的目的不是返回对象的只读副本吗?”

getter用于从外部提供对私有或受保护的类成员的访问。

如果您有一个类似的课程(在您的示例中)Report

public class Report {

    private List<Product> products;

    public void setProducts(List<Product> products) {
        this.products = products;
    }

    public List<Product> getProducts() {
        return products;
    }

}

getProducts使列表可以从类外部访问(因此,如果可变,则可以添加或删除元素)。尽管有争议,但通常使用Java bean来完成这种事情(考虑使用不需要不必要地公开状态信息的方法来代替getter和setter)。无论如何,请参见here,以获取有关根据Oracle的getter和setter的更多信息。

答案 1 :(得分:0)

您的列表包含可变产品对象。

您不修改任何列表。列表包含对相同可变对象的引用,您正在对这些对象进行更改。基本上是与

相同的旧问题

为避免这种情况,您可以使getProductList返回的列表。另外,您可以使Product类不可变,这将迫使您重新考虑您的方法。

public List<Product> getProductList() {
    List<Product> copies = new ArrayList<>();
    for (Product product: productList)
        copies.add(new Product(product)); // add this constructor

    return copies;
}