I'm reading J. Bloch's effective Java and now I'm at the section about avoiding returning nulls, but returning empty collections. This's the code example form the section:
// The right way to return a copy of a collection
public List<Cheese> getCheeseList() {
if (cheesesInStock.isEmpty())
return Collections.emptyList(); // Always returns same list
else
return new ArrayList<Cheese>(cheesesInStock);
}
I really cannot understand what's wrong with just returning the cheesesInStock if cheesesInStock.isEmpty(). why is it better to return the predefined Collections.emptyList(). What kind of troubles we may get into, if we return cheesesInStock instead.
If the method returns cheesesInStock - the caller may add some cheese to the list.
It is a bad practice as you may want to control adding procedure.
Because
you will save resources with Collections.emptyList(); that has a singletton pattern.
it's type-safe
list is immutable (cannot be modified)
Also taking a look at the API you can find:
Returns the empty list (immutable). This list is serializable.
This example illustrates the type-safe way to obtain an empty list:
List<String> s = Collections.emptyList();
Implementation note: Implementations of this method need not create a separate List object for each call. Using this method is likely to have comparable cost to using the like-named field. (Unlike this method, the field does not provide type safety.)
The idea here is more about safe object publication or sharing, returning a reference to a mutable list allows the caller to mutate the original list which is usually a bad idea. If the list or the object in general is immutable then you don't need to do that, String for example is immutable and hence sharing it is safe.
String getString(){
return someString; // no need to copy
}
Shared mutable state comes with two main headaches:
Its hard to check program's correctness when things can be mutated from anywhere.
Thread safety becomes harder because it requires synchronisation which is usually hard and expensive.
If you return cheesesInStock directly, you return a reference to the same List that the one you're object is having (and not a copy of it); so any changes made by someone acquiring this list will reflect in the internal representation of the object. Example:
List<Cheese> list = myObject.getCheeseList();
list.add(new Cheese()); // this also affects the list inside myObject
To prevent from this, it is a good practice to return a copy of the list instead with new ArrayList<Cheese>(previousList). Note that instead of returning a new List, you could also return an unmodifiable view of the List, using Collections.unmodifiableList: this has the same goal - prevent a calling code to modify the internal representation of the object.
The advantage of returning Collections.emptyList(); instead of returning new ArrayList<Cheese>(emptyList) is that you avoid the creation of another object. Also, Collections.emptyList(); represents an immutable List.
The cheesesInStock List can be structurally modified later but a Collections.emptyList() returns an empty list which cannot be structrally modified later.Collections.emptyList() returns EmptyList ,some of the functions are :-
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E get(int index) {
throw new IndexOutOfBoundsException("Index: "+index);
}
Related
public class TestImmutableCollection {
static class Helper {
int val;
public Helper(int val) {
this.val = val;
}
#Override
public String toString() {
return String.valueOf(val);
}
}
public static void main(String[] args) {
List<Helper> origin = new ArrayList<>();
origin.add(new Helper(10));
origin.add(new Helper(11));
origin.add(new Helper(13));
ImmutableList<Helper> ul = ImmutableList.copyOf(origin);
ul.get(0).val = 15;
System.out.println(ul);
System.out.println(origin);
}
}
I was asked about immutability in a previous interview thus I search the Internet on Immutable Collections in Java. So I ran into this post Java Immutable Collections where quite a few people referenced that Guava has a better and safer implementation of the Immutable Collections.
Before using guava I have already tested the above code using JDK's built-in UnmodifiableList which turned out the UnmodifiableList is just a wrapper of the original list so that the content of both list will be updated if I use get to access the inner element and then update the field of the element object.
As people stated in the previous post:
Unlike Collections.unmodifiableList(java.util.List<? extends T>),
which is a view of a separate collection that can still change, an
instance of ImmutableList contains its own private data and will never
change.
Then I test the code with guava ImmutableList. But still it gave the same result. Both the content of the ImmutableList created by copyOf() and the original list has changed.
I am quite confused why turns out like that. Am I understanding the scope of immutability here? The change of content of the elements in the Collection won't be judge as a change to the Collection here? But the doc of guava says so absolutely that it will never change.
If so, what is the difference between guava ImmutableList and JDK's UnmodifiableList in this case?
Hope someone can draw a light on that. Appreciate that.
Updated: Well, I know it is not a good design not to add any access constraint on fields of a class. But just try to image a realistic case where the Helper can be like an Account of a user, the filed can be the user's username, you will certainly provide a method to update this username field , right? Then in this case how can I just show the info of the accounts in the list without letting the caller to modify the content of the element in this list?
Neither UnmodifiableList nor ImmutableList guarantee that elements stored in those collections won't ever change. The collections themselves are immutable, not elemenets stored in them. Those collections would have to return copies of stored elements but they don't. You can't add/remove elements to those collections but you can still modify elements themselves.
A quote from Javadocs for ImmutableCollection helps here a lot:
Shallow immutability. Elements can never be added, removed or replaced in this collection. This is a stronger guarantee than that of Collections.unmodifiableCollection(java.util.Collection<? extends T>), whose contents change whenever the wrapped collection is modified.
Basicly UnmodifiableList is just a wrapper around some other collection. If you somehow get hold of that wrapped collection, you can modify it (adding or removing elements) and those changes will be reflected in the UnmodifiableList itself.
ImmutableList on the other hand copies references to all elements of the original collection and doesn't use it anymore. The newly created ImmutableList and the original collection are thus separate, you can modify the original one (adding or removing elements) and won't see any changes in the ImmutableList.
And an extra quote from the Javadocs for ImmutableCollection:
Warning: as with any collection, it is almost always a bad idea to modify an element (in a way that affects its Object.equals(java.lang.Object) behavior) while it is contained in a collection. Undefined behavior and bugs will result. It's generally best to avoid using mutable objects as elements at all, as many users may expect your "immutable" object to be deeply immutable.
Edit to answer the question you added:
If you want caller to be able to do anything with those objects but don't want those changes to affect your original data you can make a deep copy - make copy of every single element in the collection.
Othe approach will be to write a wrapper for that Account class, with restricted access - without any setters. With a simple composition you block all modifications.
You are not modifying the list, but one of the elements inside that list!
If you do the following
public static void main(String[] args) {
List<Helper> origin = new ArrayList<>();
origin.add(new Helper(10));
origin.add(new Helper(11));
origin.add(new Helper(13));
ImmutableList<Helper> ul = ImmutableList.copyOf(origin);
ul.get(0).val = 15;
origin.add(new Helper(42)); // <-- Added another element here!
System.out.println(ul);
System.out.println(origin);
}
you will get the following output:
[15, 11, 13]
[15, 11, 13, 42]
To really achieve immutability, you should consider to also make your elements immutable.
I've been taught that if there is some method which return type is java.util.Collection extension implementation (for this example lets assume it's List interface implemented by ArrayList) I should return its new instance. To be precise let me put here an example:
public List<Something> getListOfSomething() {
List<Something> somethingsList = methodCall(); //some method execution which returns list of something
//some code
return new ArrayList<>(somethingList); //returning list implementation
}
If you look at my snippet you'll see constructor call return new ArrayList<>(somethingList).
My questions are:
Is this correct approach?
If yes (or no) - why?
If it depends - depends on what?
I've been looking for an answer through the Stack, but couldn't even find similar question.
It is safe, as it cannot modify the originally returned list.
However that normally is the resposibility of the called method itself.
You would not like having copies of copies, or needlessly copy.
Under some circumstances you could do:
return Collections.unmodifiableList(somethingList);
The returned list is no longer modifiable, but that might not suit the caller.
I would leave the responsibility to the methodCall to not expose internal data.
If it is a private method, and yours is a public one, then it might be your responsibility. Check whether the data stems from a field, as then you risk exposing internal data to the exterior world.
And finally you could return a Stream which is best.
public Stream<Something> getStreamOfSomething() {
List<Something> somethingsList = methodCall();
...
return somethingList.stream();
}
A Stream gives no access to the List object whether it exposes an internal field to the outside world or not. It everytime gives a new stream/iteration through the list, and one could turn it in a list, or whatever.
Also if you need to do something with the elements of the original list, it is likely you would call .stream() on the list anyway. Otherwise:
List<Something> somethingsList = obj.getStreamOfSomething().collect(Collectors.toList());
If I have a list, and I want to have a method that returns the list without exposing the actual list itself, what would be the best way to do that?
public class open {
private List<Open> users;
public open() {
this.users = new ArrayList<Open>();
}
public List<Open> getUsers() {
//return a copy of the list}
So basically I'd need a copy of the list... I'm guessing that using iterators might be the way to go, but is there a more efficient way to do it?
There are a number of options.
You could use the copy constructor:
return new ArrayList<>(users);
This will explicitly copy the List and return the copy. I wouldn't recommend this unless you really need a mutable copy - it's O(n) obviously.
A much more efficient approach is to use the Collections utility class, this provides a way to return an immutable view:
return Collections.unmodifiableList(users);
As this is a view, return method is O(1) rather than O(n) so more efficient. It deals with ensuring that you cannot modify the List, neither via add & remove etc nor via, for example, Iterator.remove.
It's unnecessary to create a copy of the list. You can return an unmodifiable view of the list with Collections.unmodifiableList.
return Collections.unmodifiableList(users);
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
Here a beginners question.
Is there any difference in JAVA between passing an object as argument to a method or returning that object from the method. For instance: Is it better to pass a List as an argument and fill it in the method or just allow the method to return a list?
My guess is that it should be no difference since a reference is returned and nothing is copied. But is there something more subtle behind?
thanks in advance
Altober
Many of the comments seem to have misunderstood what you mean.
I believe you're asking the difference between
public void myMethod(List list) {
list.add(new Object());
}
and
public List myMethod() {
List list = new ArrayList();
list.add(new Object());
return list;
}
Correct me if I'm wrong.
There is no rule to say which one is right. It all depends on how you wish to design your program. The latter method won't allow you to use existing Lists, so there may be performance issues to be considered.
You can also perform method chaining when returning values from a method, so sometimes you could take both a parameter and returning a value. A variation from this is a method that will use an existing List if it is passed as a parameter, but create a new List if the parameter is null. However this can be confusing to the caller.
First, there is no "pass by reference" in Java: the language is passing references by value (it is not the same thing).
The answer to your question is "it depends": passing an object as an argument to a method lets you reuse the same object in multiple invocations, while returning an object forces the method to supply a new or an existing object to the caller.
Consider this example: you are collecting data from several methods, and you need to put all the data in one list. You can have methods returning lists with their data
interface DataSource {
void supplyData(List<Data> list);
}
or you could pass these methods a list, and have them add their data to the same list:
interface DataSource {
List<Data> supplyData();
}
In the first case, you could loop through multiple data sources, passing them the same list:
List<Data> bigList = new ArrayList<Data>();
foreach (DataSource s : mySources) {
s.supplyData(bigList);
}
In the second case, you would need to get individual lists from the calls of supplyData, and put their content in a big list that you keep in your loop:
List<Data> bigList = new ArrayList<Data>();
foreach (DataSource s : mySources) {
List<Data> tmp = s.supplyData();
bigList.addAll(tmp);
}
In the second case each invocation creates a temporary list tmp that gets discarded after its content is added to the big list.
Note that passing an existing list is not necessarily a better solution - in fact, there are situations when you should avoid that.
For example, when you deal with externally supplied plug-ins, you should prefer the second strategy. Otherwise, a malicious implementation of the DataSource interface would be able to manipulate the common list in ways not expected by your program, such as adding its items ahead of everyone else's, removing items that came from other sources, examining items from other sources, and so on.
In addition to the answer from dasblinkenlight, which is correct (it depends), returning a list from the method also has advantages over passing a list as argument.
By passing a list as argument, the caller has the responsibility to choose the appropriate List implementation, to initialize it to the appropriate size, and to pass a list that is compatible with the algorithm of the called method. Often, the caller doesn't have the knowledge that is necessary to make the good choice.
Whereas if the called method returns a list, it can:
return Collections.emptyList() if nothing has to be returned
return a well-dimensioned ArrayList
return a subList or an unmodifable view or transformed view of a list it already has in memory, instead of making a copy
do anything with the list it creates without fearing that the list passed as argument is unmodifiable, or fixed-size, or already contains elements.
No difference, both are references to list object.
Personally I prefer that results are given by return and leave the arguments. But that might force you to create a new list, and that might cost you (performance, memory).
Returning allows for chaining.
As you are probably aware, everything in Java is pass-by-value.
Is there any difference in JAVA between passing an object as argument to a method or returning that object from the method?
No real difference as it is the reference that is being passed around in both cases.
Is it better to pass a List as an argument and fill it in the method or just allow the method to return a list?
Depends on your requirements I guess. Does the method require a list as input or can it construct it entirely by itself?
My guess is that it should be no difference since a reference is returned and nothing is copied?
Strictly speaking, this is not true as a copy of the reference is returned.
What is the use of Collections.singletonList() in Java? I understand that it returns a list with one element. Why would I want to have a separate method to do that? How does immutability play a role here?
Are there any special useful use-cases for this method rather than just being a convenient method?
The javadoc says this:
"Returns an immutable list containing only the specified object. The returned list is serializable."
You ask:
Why would I want to have a separate method to do that?
Primarily as a convenience ... to save you having to write a sequence of statements to:
create an empty list object
add an element to it, and
wrap it with an immutable wrapper.
It may also be a bit faster and/or save a bit of memory, but it is unlikely that these small savings will be significant. (An application that creates vast numbers of singleton lists is unusual to say the least.)
How does immutability play a role here?
It is part of the specification of the method; see above.
Are there any special useful use-cases for this method, rather than just being a convenience method?
Clearly, there are use-cases where it is convenient to use the singletonList method. Indeed, any program where you need to use an immutable list with one element is a valid use-case. (It takes roughly zero imagination to think of one.)
But I don't know how you would (objectively) distinguish between an ordinary use-case and a "specially useful" one ...
From the javadoc
#param the sole object to be stored in the returned list.
#return an immutable list containing only the specified object.
example
import java.util.*;
public class HelloWorld {
public static void main(String args[]) {
// create an array of string objs
String initList[] = { "One", "Two", "Four", "One",};
// create one list
List list = new ArrayList(Arrays.asList(initList));
System.out.println("List value before: "+list);
// create singleton list
list = Collections.singletonList("OnlyOneElement");
list.add("five"); //throws UnsupportedOperationException
System.out.println("List value after: "+list);
}
}
Use it when code expects a read-only list, but you only want to pass one element in it. singletonList is (thread-)safe and fast.
Here's one view on the singleton methods:
I have found these various "singleton" methods to be useful for passing a single value to an API that requires a collection of that value. Of course, this works best when the code processing the passed-in value does not need to add to the collection.
To answer your immutable question:
Collections.singletonList will create an immutable List.
An immutable List (also referred to as an unmodifiable List) cannot have it's contents changed. The methods to add or remove items will throw exceptions if you try to alter the contents.
A singleton List contains only that item and cannot be altered.
If an Immutable/Singleton collections refers to the one which having only one object and which is not further gets modified, then the same functionality can be achieved by making a collection "UnmodifiableCollection" having only one object. Since the same functionality can be achieved by Unmodifiable Collection with one object, then what special purpose the Singleton Collection serves for?
singletonList can hold instance of any object. Object state can be modify.
List<Character> list = new ArrayList<Character>();
list.add('X');
list.add('Y');
System.out.println("Initial list: "+ list);
List<List<Character>> list2 = Collections.singletonList(list);
list.add('Z');
System.out.println(list);
System.out.println(list2);
We can not define unmodifiableList like above.