Reputation: 818
I have a static
List property (e.g. ArrayList<String>
) which is passed among multiple methods to add/modify elements. There are already few methods and in near future many methods to come.
So I need to ensure that no method could clear the list. So far I have overridden clear()
method with empty method body.
My approach is as bellow:
private static List<String> singleList = new ArrayList<String>(){
@Override
public void clear() {
//here I disabled clear() with empty method
};
};
public static void main(String[] args) throws IOException {
addNumber(singleList);
addDigit(singleList);
addSign(singleList);
System.out.println(singleList);
}
private static void addNumber(List<String> singleList) {
singleList.add("1");
singleList.add("2");
}
private static void addDigit(List<String> singleList) {
singleList.add("A");
singleList.add("B");
singleList.clear();// Suppose, this line wrote accidentally, and I need to prevent it.
}
private static void addSign(List<String> singleList) {
singleList.add("+");
singleList.add("/");
}
Is there any better option to do that?
Please suggest me.
Upvotes: 0
Views: 465
Reputation: 5187
For this purpose, you could use immutability. Instead of mutating the list, just return always an immutable one with the elements you want to have. You could use, for example, Guava ImmutableList, create a builder and add the previous list and/or new elements.
Guava docs about the clear
method:
Guaranteed to throw an exception and leave the collection unmodified.
Upvotes: 3
Reputation: 140318
A better approach than extending ArrayList
- although more verbose - is to compose ArrayList
with a class which prevents clearing.
Basically, create a class which implements List
, and delegates all of its method calls to another List
instance, other than clear
:
final class CannotClearList<E> implements List<E> {
private final List<E> delegate;
CannotClearList(List<E> delegate) {
this.delegate = delegate;
}
@Override public boolean add(E element) {
return delegate.add(element);
}
@Override public E get(int i) {
return delegate.get(i);
}
@Override public void clear() {
// Cannot "do nothing": that violates the definition of the
// Collection.clear() method.
throw new UnsupportedOperationException();
}
// etc, for all other methods.
}
Aside from the advantage that you aren't now restricted to having an ArrayList
that you cannot clear (you could reuse it e.g. for a LinkedList
), the real advantage in doing this is that in order to prevent clear()
from working, you also have to prevent lists returned by List.subList
from having clear()
called on them.
If you have prevented clear()
by extending ArrayList
, you would need to then create another class which prevents clear()
on the sublist also. However, with CannotClearList
above, you can simply wrap the sublist in another CannotClearList
:
@Override public List<E> subList(int from, int to) {
return new CannotClearList<>(delegate.subList(from, to));
}
Note that clear()
is not the only way to clear a list. You can also:
remove
;Iterator
or ListIterator
and call remove()
whilst iterating that;retainAll(Collection<?>)
with an empty collection (or a collection with no elements in common) as the argument.You should consider carefully whether you also want to prevent these cases.
Upvotes: 2
Reputation: 426
You can create your own UnClearableList
which extends ArrayList
- then in UnClearableList
simply override the clear()
method and do nothing in it (or possibly throw an exception, depending on your design).
Then use the UnClearableList when you are in such "I want to allow add / remove but no clear of my lists" cases.
Your way of doing it is technically correct. Doing this with a special UnClearableList lets you reuse it in other classes. If this is just a school exercise then it is not really necessary.
Upvotes: 0
Reputation: 533530
I would add an UnsupportedOperationException
to make sure the code which does call clear()
is corrected.
If the code relies on clear()
working, it shouldn't be using that collection.
If the code doesn't need clear()
it shouldn't be calling it.
Upvotes: 2
Reputation: 1053
Creating a new type or overloading an existing one (as you did) is the usual approach. Furthermore the interface List
explicitly allows disabling clear
as it is an optional operation.
From the JavaDoc:
/**
* Removes all of the elements from this list (optional operation).
* The list will be empty after this call returns.
*
* @throws UnsupportedOperationException if the <tt>clear</tt> operation
* is not supported by this list
*/
void clear();
Upvotes: 0