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.
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.
Is it possible to find out if some a list is fixed size or not?
I mean, for example this code:
String[] arr = {"a", "b"};
List<String> list = Arrays.asList(array);
returns fixed size List backed by an array. But is it possible to understand programmatically if List is fixed-size or not without trying to add/remove elements and catching the exception? For example:
try {
list.add("c");
}
catch(UnsupportedOperationException e) {
// Fixed-size?
}
A list created from a String[] by
List<String> list = Arrays.asList(array);
will have Arrays as enclosing class, while one created by for example new ArrayList() won't have the enclosing class. So the following should work to check if the List was produced as a result of calling Arrays.toList():
static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) {
return Arrays.class.equals(l.getClass().getEnclosingClass());
}
Beware that this method relies on undocumented behavior. It will break if they added another nested List subclass to the Arrays class.
Is it possible to find out if some list is fixed size or not?
In theory - No. Fixed sizedness is an emergent property of the implementation of a list class. You can only determine if a list has that property by trying to add an element.
And note that a simple behavioral test would not reliably distinguish between a fixed sized list and a bounded list or a list that was permanently or temporarily read-only.
In practice, a fixed sized list will typically have a different class to an ordinary one. You can test the class of an object to see if it or isn't a specific class. So if you understand what classes would be used to implement fixed sized lists in your code-base, then you can test if a specific list is fixed sized.
For example the Arrays.asList(...) method returns a List object whose actual class is java.util.Arrays.ArrayList. That is a private nested class, but you could use reflection find it, and then use Object.getClass().equals(...) to test for it.
However, this approach is fragile. Your code could break if the implementation of Arrays was modified, or if you started using other forms of fixed sized list as well.
No.
The List API is identical regardless of whether a List is expandable or not, something that was deliberate.
There is also nothing in the List API that allows you to query it to determine this feature.
You can't completely reliably determine this information by reflection, because you will be depending on internal details of the implementation, and because there is an unbounded number of classes that are potentially fixed-size. For example, in addition to Arrays.asList, there is also Arrays.asList().subList, which happens to return a different class. There can also be wrappers around the base list like Collections.checkedList, Collections.synchronizedList and Collections.unmodifiableList. There are also other fixed-size lists: Collections.emptyList, Collections.singletonList, and Collections.nCopies. Outside the standard library, there are things like Guava's ImmutableList. It's also pretty trivial to hand-roll a list for something by extending AbstractList (for a fixed-size list you need only implement the size() and get(int) methods).
Even if you detect that your list is not fixed-size, the specification of List.add allows it to refuse elements for other reasons. For example, Collections.checkedList wrappers throw a ClassCastException for elements of unwanted type.
And even if you know your list is expandable, and allows arbitrary elements, that doesn't mean you want to use it. Perhaps it's synchronized, or not synchronized, or isn't serializable, or it's a slow linked list, or has some other quality that you don't want.
If you want control over the type, mutability, serializability, or thread-safety of the list, or you want to be sure that no other code has kept a reference to it, the practice is that you create a new one yourself. It's not expensive to do so when unnecessary (memcopies are blazing fast), and it lets you reason more definitely about your code will actually do at runtime. If you'd really like to avoid creating unnecessary copies, try whitelisting instead of blacklisting list classes. For example:
if (list.getClass() != ArrayList.class) {
list = new ArrayList<>(list);
}
(Note: That uses getClass instead of instanceof, because instanceof would also be true for any weird subclasses of ArrayList.)
There are immutable collections in java-9, but there is still no common #Immutable annotation for example or a common marker interface that we could query to get this information.
The simplest way I can think of would be simply to get the name of the class of such an instance:
String nameList = List.of(1, 2, 3).getClass().getName();
System.out.println(nameList.contains("Immutable"));
but that still relies on internal details, since it queries the name of the common class ImmutableCollections, that is not public and obviously can change without notice.
I need some class/interface name that describes an immutable, ordered set (in input order, like LinkedHashSet). I can of course just use the class like this:
class Foo {
public final Set<Long> frozenOrderedSet;
public Foo(List<Long> input) {
frozenOrderedSet = Collections.unmodifiableSet(new LinkedHashSet(input));
}
}
But this would not clarify my approach. I would like to make it clear to everyone reading the source that the Set is unmodifiable and unique while maintaining it's order with for(Long l : set){}.
Guava's ImmutableSet provides a high-performance, immutable Set with reliable, user-specified iteration order. There are also variations like ImmutableSortedSet.
The simplest way would be extend Set to create a custom immutable Set.
public CustomImmutableSet(){ return Collections.unmodifiableSet(new
LinkedHashSet(input)); }
This way it will make it clear to everyone reading the source that the Set is unmodifiable and unique
Bozho in question Java Immutable Collections:
Unmodifiable collections are usually read-only views (wrappers) of
other collections. You can't add, remove or clear them, but the
underlying collection can change.
Immutable collections can't be changed at all - they don't wrap
another collection - they have their own elements.
Here's a quote from guava's ImmutableList
Unlike Collections.unmodifiableList(java.util.List),
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.
So, basically, in order to get an immutable collection out of a
mutable one, you have to copy its elements to the new collection, and
disallow all operations.
So Basically you might create subclass of class TreeSet and override all :add, remove etc. methods to just throw an Exception saying that this is immutable collection. Also you would have to create copying constructor in this class with one parameter TreeSet setToCopyFrom.
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.
I was looking around for some elegant solution to removing null values from a List. I came across the following post, which says I can use list.removeAll(Collections.singletonList(null));
This, however, throws an UnsupportedOperationException, which I'm assuming is because removeAll() is attempting to do some mutative operation on the immutable singleton collection. Is this correct?
If this is the case, what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
Thanks in advance.
It works like a charm:
List<String> list = new ArrayList<String>();
list.add("abc");
list.add(null);
list.add("def");
list.removeAll(Collections.singletonList(null));
System.out.println(list); //[abc, def]
Indeed Collections.singletonList(null) is immutable (which is unfortunately hidden in Java[1]), but the exception is thrown from your list variable. Apparently it is immutable as well, like in example below:
List<String> list = Arrays.asList("abc", null, "def");
list.removeAll(Collections.singletonList(null));
This code will throw an UnsupportedOperationException. So as you can see singletonList() is useful in this case. Use it when client code expects a read-only list (it won't modify it) but you only want to pass one element in it. singletonList() is (thread-)safe (due to immutability), fast and compact.
[1] E.g. in scala there is a separete hierarchy for mutable and immutable collections and API can choose whether it accept this or the other (or both, as they have common base interfaces)
To answer your actual question :
what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
The typical use is if you have one element and want to pass it to a method that accepts a List, ie
public void registerUsers(List<User> users) {...}
User currentUser = Login Manager.getCurrentUser();
registerUsers(Collections.singletonList(currentUser));
The removeAll() is a special case for this.
Has your list been protected with
Collections.unmodifiableList(list)
Because if you have protected it and try to modify it later you get that error.