0

次のようなメソッドを呼び出したい場合:

  List f(List l){
      l.add(new Object());
      return l;
  }

メソッドを呼び出す場合を除いて、すべて問題ありません。実際にその引数を変更します。とにかくその周りにありますか?

// suppose l is instantiated at this point
log.info(l.count());// prints 0
f(l);
log.info(l.count());// prints 1

javaでlを変更しないようにfを宣言する方法はありますか?

l に対してディープ クローンを実行して渡すことができることはわかっていますが、l が非常に大きい場合、この操作はコストがかかります。

4

5 に答える 5

6

それを変更するメソッドを呼び出さないでください。コピーせずに、そのようなメソッドが何をすることを期待しますか? 異なる動作をする (たとえば、 が呼び出されたときに何もしないadd) か、例外をスローする必要があります。変更不可能なリストにラップすることで例外をスローさせることができます...しかし、メソッドの目的がコレクションを変更することである場合、おそらく例外をスローしたくないでしょう...

これが少し陳腐な答えのように聞こえることは承知していますが、考えなければならないことの核心に本当に到達することを願っています: 変更すべきではないコレクションがあり、変更を試みるメソッドを呼び出したい場合コレクションを変更するには、そもそもそのメソッドを呼び出す理由を検討する必要があります。

難しい部分は、どのメソッドがコレクションを変更するかを知ることであることを理解しています-そして、それは、変更不可能なラッパーを防御的に作成するか、関連するすべてのメソッドが正しく文書化されていることを確認できる場所です。

于 2011-02-21T17:24:17.727 に答える
2

変更不可能なリストを使用します:

log.info(l.count());
f(Collections.unmodifiableList(list));
log.info(l.count());

メソッド内でリストを変更しようとすると、UnsupportedOperationException.

于 2011-02-21T17:23:39.537 に答える
2

元のリストを変更したくない場合は、変更しないでください。

代わりに、コピーを変更できます。

List f(List l){
  l = new ArrayList(l); // the original will not be changed now.
  l.add(new Object());
  return l;
}
于 2011-02-21T17:25:10.160 に答える
0

これが、常に仕様を書くことから始めて、API について提供されたものに注意を払う必要がある理由です。これは、メソッドの仕様に記載されています。

リストに変更が加えられないように強制したい場合は、変更を試みると仕様に記載されていることを無視して (メソッド自体を作成していないと仮定して)、 as でラップしCollections.unmodifiableList(l);、スローされた例外を as として処理します。他の人が提案しました。

反対側にいて、メソッドを書いていて、リストの内容を変更しないようにしたい場合は、変更ステートメントを書か、仕様でそれについて言及するようにしてください。

于 2011-02-21T18:08:18.207 に答える
0

元のリストがそれ自体では変更されないことがわかっていて、元のリストのすべての内容と 1 つの新しい要素を含む新しいリストが必要な場合は、次のように両方のラッパーを使用することを検討できます。

/**
 * 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());
}

元のリストが変更されると、新しいリストも変更されます。これは仕様によるものです。

元のリストがランダム アクセスなしのリストである場合は、AbstractSequentialList から継承し、get メソッドの代わりに委譲 ListIterator を実装することをお勧めします。

于 2011-02-22T00:35:45.597 に答える