Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在java方法调用中保持参数不变_Java_Const Correctness_Mutability - Fatal编程技术网

在java方法调用中保持参数不变

在java方法调用中保持参数不变,java,const-correctness,mutability,Java,Const Correctness,Mutability,如果我想调用这样的方法: List f(List l){ l.add(new Object()); return l; } /** * an immutable wrapper around a list with an added element at the end. */ class ImmutableListWrapper<E> extends AbstractList<E> { private final List

如果我想调用这样的方法:

  List f(List l){
      l.add(new Object());
      return l;
  }
/**
 * an immutable wrapper around a list with an added element at the end.
 */
class ImmutableListWrapper<E> extends AbstractList<E> {

    private final List<E> delegate;
    private final E lastElement;

    public ImmutableListWrapper(List<E> start, E last) {
       this.delegate = start;
       this.lastElement = last;
    }


    public E get(int index) {
       if(index == delegate.size()) {
           return lastElement;
       }
       return delegate.get(index);
    }

    public int size() {
        return delegate.size() + 1;
    }
}

public List<Object> f(List<Object> l) {
    return new ImmutableListWrapper<Object>(l, new Object());
}
一切都很好,但如果我调用这个方法,它实际上修改了它的参数,这有什么关系吗

// suppose l is instantiated at this point
log.info(l.count());// prints 0
f(l);
log.info(l.count());// prints 1
在java中是否有声明f以保持l不变的方法

我知道我可以在l上执行深度克隆并将其传递,但在l非常大的情况下,此操作非常昂贵。

使用:


如果您试图在方法中修改列表,您将得到一个
不支持操作异常

好吧,不要调用会修改它的方法。如果不进行复制,您希望这种方法做什么?它要么表现不同(例如,调用
add
时不做任何事情),要么抛出异常。您可以通过将其包装在不可修改的列表中,使其引发异常。。。但是,如果该方法的目的是更改集合,您可能不希望抛出异常

我知道这听起来有点老套,但我希望它能真正触及你需要思考的核心:如果你有一个不应该修改的集合,你想调用一个试图修改集合的方法,你应该首先考虑你为什么要调用这个方法


我知道最困难的部分是知道哪些方法会修改集合,这就是你可以防御性地创建一个不可修改的包装器,或者确保所有相关方法都被正确记录的地方。

如果你不想更改原始列表,不要更改它

您可以改为更改副本

List f(List l){
  l = new ArrayList(l); // the original will not be changed now.
  l.add(new Object());
  return l;
}

这就是为什么您应该总是从编写规范开始,并充分注意提供给您的关于API的规范。这将在方法规范中列出

如果您想强制列表不做任何更改,不管规范是否说它将尝试这样做(假设您没有编写方法本身),请将其包装为
Collections.unmodifiableList(l)并按照其他人的建议处理抛出的异常


如果你在另一边-编写方法,并且你想确保你不更改列表的内容-只需不编写任何修改语句,并确保在规范中提到这一点。

如果你知道原始列表本身不会更改,并且需要一个新的列表,包含原始列表的所有内容,另外还有一个新元素,您可以考虑在两个周围都使用一个包装器,例如:

  List f(List l){
      l.add(new Object());
      return l;
  }
/**
 * an immutable wrapper around a list with an added element at the end.
 */
class ImmutableListWrapper<E> extends AbstractList<E> {

    private final List<E> delegate;
    private final E lastElement;

    public ImmutableListWrapper(List<E> start, E last) {
       this.delegate = start;
       this.lastElement = last;
    }


    public E get(int index) {
       if(index == delegate.size()) {
           return lastElement;
       }
       return delegate.get(index);
    }

    public int size() {
        return delegate.size() + 1;
    }
}

public List<Object> f(List<Object> l) {
    return new ImmutableListWrapper<Object>(l, new Object());
}
/**
*围绕列表的不可变包装器,末尾添加了一个元素。
*/
类ImmutableListWrapper扩展了AbstractList{
非公开最终名单代表;
最后一个要素;
公共ImmutableListWrapper(列表开始,E最后){
this.delegate=start;
this.lastElement=last;
}
公共E-get(int索引){
if(index==delegate.size()){
返回最后一个元素;
}
返回delegate.get(索引);
}
公共整数大小(){
返回delegate.size()+1;
}
}
公开名单f(名单l){
返回新的ImmutableListWrapper(l,new Object());
}
如果原始列表更改,新列表也会更改,这是出于设计


如果您的原始列表是非随机访问列表,那么您最好继承AbstractSequentialList并实现一个委托ListIterator,而不是get方法。

这将导致f()失败,而不是生成一个能产生所需结果的工作f()。+1-您可以进行修改,也可以进行新的修改。您不能同时更改和更改对象。我无法说出我正在执行的方法的原因是,我正在针对接口进行编码。我的库的用户将提供实现。我正在寻找一些类似C++中的const关键字的例子,在这里强制我的库的用户不调用任何在我的参数中没有标记为const的方法。因此,如果他这样做,他会得到一个编译时错误。一个更好的选择是让他得到一份我名单的不稳定副本,然后他想用它做什么就做什么。在我的使用案例中,我有一个回调列表,我想将我的列表传递给所有回调,它们中的任何一个都不应该更改列表。综上所述,我认为传递一个不可修改的列表是一个选项,不幸的是,在运行时会出现异常,而不是编译时错误。如果我有另一个物体,我将不得不用类似的方式包装它。不太理想,但从我所知道的和你的答案来看,没有更好的选择。@Charbel:听起来你的界面应该是一个不可变列表(来自Guava)或类似的东西。但从根本上说,我希望一个操作是否应该修改集合是相当明显的。见鬼,即使类型系统没有明确说明,接口文档也应该如此。