if I want to call a method like this:
List f(List l){
l.add(new Object());
return l;
}
All is fine except if I call the method, it actually modifies its argument, is there anyway around that?
// suppose l is instantiated at this point
log.info(l.count());// prints 0
f(l);
log.info(l.count());// prints 1
is there anyway to declare f in a way to keep l unchanged in java?
I know that I can perform a deep clone on l and pass it, but in cases where l is really big, this operation is expensive.
Well, don't call a method which would modify it. What would you expect such a method to do, without copying? It would either have to behave differently (e.g. not doing anything when add is called) or throw an exception. You can make it throw an exception by wrapping it in an unmodifiable list... but if the purpose of the method is to change the collection, you probably don't want an exception to be thrown...
I know this sounds like a bit of a trite answer, but I hope it really gets to the heart of what you need to think about: if you have a collection which shouldn't be modified, and you want to call a method which tries to modify a collection, you should be considering why you want to call that method in the first place.
I do understand that the difficult part is knowing which methods will modify the collection - and that's where you can either defensively create an unmodifiable wrapper, or make sure all the relevant methods are documented correctly.
Use an unmodifiable list:
log.info(l.count());
f(Collections.unmodifiableList(list));
log.info(l.count());
If you try to modify the list within the method, you will get an UnsupportedOperationException.
If you don't want to change the original list, don't change it.
You can instead change a copy.
List f(List l){
l = new ArrayList(l); // the original will not be changed now.
l.add(new Object());
return l;
}
This is why you should always start with writing a specification and take good notice of the one provided to you about APIs. This would be listed in the specification of the method.
If you want to force that no changes are made to your list, disregarding that the spec says it will attempt to do so (assuming you did not write the method itself), wrap it up with as an Collections.unmodifiableList(l); and handle the thrown exceptions, as the others suggested.
If you are on the other side - writing the method and you want to make sure you don't change the contents of the list - just don't write any modifying statements and make sure to mention that in the spec.
If you know that your original list does not change by itself, and want a new List which contains all contents of the original list and additionally your one new element, you could consider using a wrapper around both, like this:
/**
* 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());
}
If the original list changes, the new list changes too, this is by design.
If your original list is a no-random-access list, then you would better inherit from AbstractSequentialList and implement a delegating ListIterator instead of a get-method.
Related
I would like to find an API like Apache Commons that will easily and always return a collection.
The intent is to produce code that doesn't require NPE checks or CollectionUtils.isNotEmpty checks prior to collection iteration. The assumption in the code is to always guarantee a list instance thus eliminating code complexity for every collection iteration.
Here's an example of a method, but I would like an API instead of rolling my own.
private List<Account> emptyCollection(
List<Account> requestedAccounts) {
if (CollectionUtils.isNotEmpty(requestedAccounts)) {
return requestedAccounts;
} else {
return new ArrayList<Account>();
}
}
I would like to find a generic API / method that could be used for any class generically.
Here are some of my research classes inside commons that may help me do the trick.
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/TransformerUtils.html
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/CollectionUtils.html
Maybe the .collect might work using a transformer.
I'm open to using alternative API's as well.
Is this an example of what you mean?
public static <T> List<T> nullToEmpty(List<T> list) {
if (list != null) {
return list;
}
return Collections.emptyList();
}
Your question is a bit hard to understand, Do you simply want to avoid NPE, or also want to avoid CollectionUtil.isNotEmpty ?
The first is very easy, the second not so, because you essentially want to guarantee that your API will always return a Collection with at least one element.
That is a business centric constraint IMO, and not something you can guarantee via an API contract.
If all you want to avoid is NPE, you can use java.lang.Collections.EMPTY_(SET|MAP|LIST), classes. But mind you , these are immutable, i.e. the calling code, can't add objects to a collection returned this way. If you want the calling code to mutate the Collection (i.e. add/remove/update elements), then you'll have to return a zero element concrete implementation of your LIST|MAP|SET etc.
private final Map q;
public Info()
{
this(Collections.EMPTY_MAP);
}
public Info(final Map q)
{
this.qualifiers = new HashMap(q);
}
public Map getQ()
{
return Collections.unmodifiableMap(q);
}
Do I need to use Collections.unmodifiableMap() because I saw from the JAVA Docs of EMPTY_MAP that it is Immutable?
EMPTY_MAP is immutable but you still need to use Collections.unmodifiableMap(q) if Info has been instantiated with a map that is not EMPTY_MAP, using the second constructor...
No. You need to use Collections.unmodifiableMap() if you want to ensure that clients of your class never modify its internal representation - or rather, if you want to ensure that a failure will occur if a client ever tries to do so.
In the case where the internal map q is Collections.EMPTY_MAP then you wouldn't need to wrap it in a call to Collections.unmodifiableMap because it's already unmodifiable. However you have an alternative constructor that creates q as a modifiable Map, and in that case you'd need to protect it before returning it.
You can also simply return a copy of q in which case clients could modify the returned object without modifying your class's internal state nor raising an exception.
I am trying to determine what the best practices would be for an ImmutableList. Below is a simplistic example that will help drive my questions:
Ex:
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
//.. do some work
ImmutableList<Foo> fooOther = // something generated during the code
return fooOther;
}
public Collection<Foo> getFooTwo(List<Foo> fooInput){
//.. do some work
List<Foo> fooOther = // something generated during the code
return ImmutableList.copyOf(fooOther);
}
public void doSomethingOne(){
ImmutableCollection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
public void doSomethingTwo(){
Collection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
My Questions:
Which makes the most sense to use in an application? [doSomethingOne and getFooOne] or [doSomethingTwo and fooTwo]? In other words if you know you are using ImmutableCollections does it make sense to keep casting back and forth and doing copyOf(), or just use Immutable everywhere?
These examples are public methods which could imply that other people use them. Would any of these answers change if the methods were private and used internally?
If a user tries to add anything to an immutable List an exception will be thrown. Because they may not be aware of this, wouldn't it make more sense to explicitly return an ImmutableCollection instead of a Collection?
In general, it's wise not to commit to a specific implementation in your declared return type, but we think of the immutable types as an exception. There are a few reasons to declare a return type of Immutable*:
They document that you're returning a snapshot, not a live view.
They document that the caller can't mutate the result.
They document that insertion order is preserved (which may or may not be significant in your use case).
They document that the collection won't contain null.
Someone might want the asList() or reverse() method.
You may save someone a copyOf() call if he wishes to assign to an Immutable* field. (But note that, if he does include copyOf(), it will short-circuit for most immutable inputs, even if you don't declare the return type.)
Basically, I'm just cribbing from https://github.com/google/guava/wiki/TenThingsAboutImmutableCollections, which you may want to check out in its entirety.
If I understood your intentions, the proper way of designing getFooXxx for making an immutable copy of maybe-mutable-list is something like this:
/**
* Returns an <b>immutable copy</b> of input list.
*/
public ImmutableList<Foo> immutableCopyOfFoo(List<Foo> input){
return ImmutableList.copyOf(input);
}
Why?
ImmutableList.copyOf() does it's magic when given list is immutable,
method signature explicitly says what it does,
method returns ImmutableList which is, in fact, an ImmutableCollection but why would you like to hide information about ImmutableList from user? If he wants, he'll write Iterable foo = immutableCopyOfFoo(mutableFoo); instead, but 99% he'll use an ImmtableList,
returning an ImmutableList makes a promise - "I am immutable, and I will blow everything up if you try to change me!"
and last but not least - proposed method is unnecessary in internal use; just use
someOtherMethod(ImmutableList.copyOf(foo));
directly in your code...
You should check #ChrisPovirk's answer (and link to wiki in that answer) to know that i.e. when List<Foo> input contains nulls, you will get nasty NPE on runtime if you try to make an immutable copy...
EDIT answering comment #1:
Collection contract is less strict than List's one; i.e. Collection doesn't guarantee any order of elements ("Some are ordered and others unordered") while List does ("An ordered collection (also known as a sequence)").
If an input is a List it suggests that order is important and therefore output should guarantee the same. Imagine that:
public ImmutableCollection<Foo> immutableCopyOfFoo(List<Foo> input){
return ImmutableSortedSet.copyOf(input, someFancyComparator);
}
It doesn't smell right. If you don't care about order then maybe method signature should be immutableCopyOfFoo(Collection<Foo> input)? But it depends on concrete use case.
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
ImmutableList<Foo> fooOther= fooInput;
return ImmutableList.copyOf(fooOther);
}
This makes no sense at all. Why would you ever copy an immutable collection? The whole point of immutability is: it can't be changed, so you might as well re-use it.
public Collection<Foo> getFooTwo(List<Foo> fooInput){
ImmutableList<Foo> fooOther= ImmutableList.copyOf(fooInput);
return ImmutableList.copyOf(fooOther);
}
??? Why do it twice??? This is fine:
public Collection<Foo> getFooTwo(List<Foo> fooInput){
return ImmutableList.copyOf(fooInput);
}
ImmutableList.copyOf(Collection) is smart enough to return ImmutableList unmodified and create a new ImmutableList for everything else.
My usual approach is:
accept List for parameters (so the interface is easier to use for clients)
if performance/memory usage/thread-safety is important, copy the contents of the provided List into a data structure that is optimized for usage by your class
when returning an ImmutableList, ImmutableList should be the return type (because it gives the caller more information about how it can use the returned value)
when returning a mutable implementation of List, List should be the return type, unless something else about the return type is important (thread-safety, as a bad* example)
* It's a bad example because if your return values need to be thread-safe, it probably means something else is wrong with your code.
Replace List/ImmutableList with any of the immutable collection types.
You should always use the standard JRE classes on public interfaces. There are no extra methods on Guava's Immutable... classes so you're not gaining any compile-time safety: any attempts to make changes to those objects will only fail at run-time (but see Bart's comment). You should document in methods that return collections that they're immutable.
You should make defensive copies of lists provided on public methods if you're worried about concurrent modification, but it's OK to specify ImmutableCollection on private method arguments.
An instance of Class A has a private ArrayList. The instance is responsible for maintaining data stored in the arrayList.
private ArrayList<SomeDataStructure> myPrivateArrayList;
However, when other module ask for the data, this instance of Class A will have to pass the data the whoever asks for it, therefore, there is public function in Class A:
public ArrayList<SomeDataStructure> getMyPrivateArrayList ();
My question, how should I implement this function so that I could guarantee that those who get the arrayList through this public function won't be able to modify it (i.e., the return value is read-only)?
Thanks in advance!
I would suggest doing this instead (if you're allowed to in your situation):
private ArrayList<SomeDataStructure> myPrivateArrayList;
public List<SomeDataStructure> getMyPrivateList () {
return Collections.unmodifiableList(myPrivateArrayList)
}
Note that the exposed data structure is of type List instead of ArrayList. I think (generally speaking) the public interface of a class should not return concrete types, but rather should return interfaces. It simplifies tasks such as this one, and also reduces the amount of dependancy that one class has on the implementation of another class.
Instead of return-type ArrayList<SomeDataStructure>, use List<SomeDataStructure>. Then you can use the java.util.Collections.unmodifiableList(...) utility-method to create a read-only view of your list:
public List<SomeDataStructure> getMyPrivateArrayList()
{
return Collections.unmodifiableList(myPrivateArrayList);
}
Another option is to return a copy of your list:
public ArrayList<SomeDataStructure> getMyPrivateArrayList()
{
return new ArrayList<SomeDataStructure>(myPrivateArrayList);
}
(There are some other options as well, but those are the most common approaches.)
But keep in mind that, if SomeDataStructure is mutable, then callers of either of the above can still mutate any of the objects in your list. (That is, they can do something like obj.getMyPrivateArrayList().get(0).setProp(null).)
In your getMyPrivateArrayList () function do the following :
public List<SomeDataStructure> getMyPrivateArrayList(){
return Collections.unmodifiableList(myPrivateArrayList);
}
Collections.unmodifiableList(someList) returns read-only list.
In your calling class if you try to modify the returned list, you will get error on runtime.
eg.
If you do the following
List<SomeDataStructure> readOnlyList=getMyPrivateArrayList();
readOnlyList.add(new SomeDataStructure());
You'll get following error :
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableList.add(Collections.java:1160)
at MainClass.main(MainClass.java:14)
Do you need to get the list? Or can you simply forward some accessors to the list? You could define some public functions like get(index) which simply call the equivalent methods on your list and return the result. This is most likely what you want to do because it gives people access only to the methods you choose, and you dont have to give them the list itself or waste CPU cycles copying the data into "read-only" structures.
I have a code that read list from some paged string data. What I do not understand - why the UnsupportedOperationException is thrown on addAll() and why it's kind of random behaviour ?
I know creating target ArrayList and not adding to the returned one solves the issue, I'm looking for better understanding not a fix.
List<Event> eventList = eventTable.getEvents(); // returns ArrayList
while (hasNextPage()) {
goToNextPage();
eventList.addAll(eventTable.getEvents());
}
List<Event> is not necessarily an ArrayList<Event>. (The opposite is true though.)
The reason you get UnsupportedOperationException sometimes, is because eventTable.getEvents() sometimes returns a list that supports addAll and sometimes it doesn't.
The implementation of getEvents could for instance look like this:
if (noEventsAvailable) {
return Collections.emptyList();
} else {
List<Event> toReturn = new ArrayList<Event>();
// populate list...
return toReturn;
}
(In your comment you write // returns ArrayList. I don't know where you've got this from, but I know one thing for sure: An ArrayList will always support the addAll operation.)
The correct way to solve it is, as you mention, to do
List<Event> eventList = new ArrayList<Event>(eventTable.getEvents());
It depends on the actual implementation of List.
e.g if the underlying list was obtained using Collections.unmodifiableList() then calling addAll() or any other modification method will throw an UnsupportedOperationException.
When it throws an exception, it should show you the exact line number and source code file - you should be able to find out exactly why it's throwing an exception.
My guess is that under certain circumstances, eventTable.getEvents() returns an immutable list, or something like that - but without knowing what eventTable is, it's hard to say for sure. If you can produce a short but complete program which demonstrates the problem, that would make it a lot easier to diagnose.