I am having a list in the format
ArrayList<Integer> list = new ArrayList();
where I add and remove various elements in a loop. However, I need some structure where I can store the temporary lists so that I can access them later.
So for example, if I do System.out.print(list) it will return
[1,2,3,4]
then I need to call something like store.add(list)
and then if I add another element to the list - list.add(5) it becomes
[1,2,3,4,5]
then again
store.add(list)
and by calling System.out.print(store) it should return
[1,2,3,4]
[1,2,3,4,5]
In other words, store should be something like list within list?
List in list creating like this: List<List<Integer>> listInList = new ArrayList<List<Integer>>();
I suppose you want to have multiple versions of the same list.
You can't get that by just having a List of List.
The list will store only reference to the member lists stored inside it. So when you edit your list, all older versions will be edited as well. It's the same list behind the scene.
The correct way to use the List<List<Integer>> would be as follows.
List<List<Integer>> store = new ArrayList<>(); // Create storage for versions
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
store.add(new ArrayList<>(list)); // Add list's copy to store.
list.add(5); // Edit it as you want.
store.add(new ArrayList<>(list)); // Add list's copy to store.
System.out.println(store); // Print all versions
Output:
[[1, 2, 3, 4], [1, 2, 3, 4, 5]]
Hope this helps.
It is somewhat wasteful to store every new list, especially when the changes to the previous are very simple (e.g. additions and deletions at/from the end). You could come up with a strategy of keeping track of changes rather than storing the same information repeatedly.
First, you should decide which of the following is more important:
Have the list of lists readily available, at the expense of memory. This is desirable when you know you will need it very often and therefore cannot afford the overhead of generating it on-the-fly from history.
Use space efficiently, at the occasional cost of computing the list of lists from history. This is desirable when you make many changes and use the list of lists rarely.
The solutions already posted address 1., so here is a proposal for 2. (I will restrict the possible operations to adding and removing from the rear for the sake of brevity):
public enum Operation { ADD, REMOVE }
public class Modification {
Operation operation;
Integer element;
public Modification(Operation operation, Integer element) {
this.operation = operation; // could add some sanity checks (e.g. cannot remove from empty list)
this.element = element;
}
}
List<Integer> initialList = Arrays.asList(1, 2, 3, 4);
List<Modification> history = new ArrayList<>();
history.add(new Modification(Operation.ADD, 5));
Then you can define a function to compute the list of lists that you need:
List<List<Integer>> getAllLists (List<Integer> initialList, List<Modification> history) {
List<List<Integer>> allLists = new ArrayList<>();
allLists.add(initialList);
prevList = initialList;
for (Modification modification : history) {
prevList = new ArrayList<>(prevList);
if (modification.operation == ADD) prevList.add(modification.element);
else prevList.remove(prevList.size()-1);
allLists.add(prevList);
}
return allLists;
}
Related
I was trying this problem where we need to find the permutations of the elements in the array.
This is the leetcode problem no 46. The issue I've faced is that I'm not able to output the ans it just keeps returning a blank ArrayLists:
Code:
public List<List<Integer>> permute(int[] nums)
{
List<List<Integer>> fans = new ArrayList<>();
HashMap<Integer, Integer> fmap = new HashMap<>();
for(int i: nums){
fmap.put(i, fmap.getOrDefault(i, 0) + 1);
}
int n=nums.length;
List<Integer> ans=new ArrayList<>(n);
dfs(1, n, fmap, ans, fans);
return fans;
}
public void dfs(int cs, int ts, HashMap<Integer, Integer> fmap,List<Integer> ans, List<List<Integer>> fans)
{
if (cs > ts)
{
fans.add(ans);
return;
}
for(Integer val: fmap.keySet())
{
if (fmap.get(val) > 0)
{
fmap.put(val, fmap.get(val) - 1);
ans.add(val);
dfs(cs + 1, ts, fmap, ans, fans);
ans.remove(ans.size() - 1);
fmap.put(val, fmap.get(val) + 1);
}
}
}
Output for the test case [0,1]:
[[],[]]
The actual output should be:
[[0,1],[1,0]]
When I'm checking the "potential answer" inside the recursive method, I am able to see the correct answer. I mean, if I print the output in the dfs method, it shows the correct answer:
Change in the code:
if (cs > ts)
{
fans.add(ans);
System.out.println(fans);
return;
}
Now it's printing the value of fans:
[[0, 1]]
[[1, 0], [1, 0]]
But these values are not being updated in the fans and the returned value comes up blank.
I read someone mention this same issue, but it was for Python, and the solution in that case was to do a deep copy of the list.
I'm not sure how to do that in Java.
What I'm doing wrong?
In order to generate a list of permutations, you don't need a Map. You've only introduced redundant actions, which are not useful anyhow. If you doubt, add a couple of print-statements to visualize the map state it will always contain the same key with the value 1 (all numbers in the input are guaranteed to be unique) and it has no impact on the result.
Source of data for generating the Permutations
Besides the fact that attempt to utilize the HashMap as the source of data for generating permutations isn't working because of the bugs, it's also not a good idea because the order iteration over the keySet of HashMap is not guaranteed to be consistent.
As the uniform mean for storing the numbers that haven't yet been applied in current permutation, we can use an ArrayList. In this case because there will be no duplicates in the input (see the quote from the leetcode below), we can use a LinkedHashSet instead to improve performance. As explained below, a removal of elements will happen at before making every recursive a call, and removal from an ArrayList has a cost of O(n), meanwhile with LinkedHashSet it would be reduced to O(1).
Constraints:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
All the integers of nums are unique.
Generating the Permutations
Each generated permutation should be contained in its own list. In your code, you've created one single list which is being passed around during recursive calls and eventually every recursive branch adds the same list to the resulting list. Which obviously should not happen.
You see, the result is being printed as [[],[]]. It seems like a list containing two lists, but in fact they refer to the same empty list.
And this list is empty because every element that was added to it, is being removed after performing a recursive call:
ans.add(val);
... <- rursive call in between
ans.remove(ans.size() - 1); // removes the last element
if I print the output in the dfs method, it shows the correct answer:
Actually, it's not correct. If you take a careful look at the results, you'll see the nested lists are the same [[1, 0], [1, 0]].
The final result is blank because all recursive calls are happening between each value being added and removed (see the code snippet above). I.e. removal will be performed in revered order. That would be the last lines to be executed, not the return statements. To understand it better, I suggest you to walk through the code line by line and draw on paper all the changes done to the ans list for a simple input like [0, 1].
Instead, you should create a copy of the list containing not fully generated permutation (answer) and then add an element into the copy. So that the initial permutation (answer) remains unaffected and can be used as a template in all subsequent iterations.
List<Integer> updatedAnswer = new ArrayList<>(answer);
updatedAnswer.add(next);
And you also need to create a copy of the source of data and remove the element added to the newly created permutation (answer) in order to avoid repeating this element:
Set<Integer> updatedSource = new LinkedHashSet<>(source);
updatedSource.remove(next);
Sidenote: it's a good practice to give meaningful names to methods and variables. For instance, names cs and ts aren't informative (it's not clear what they are meant to store without looking at the code), method-name dfs is confusing, DFS is a well-known algorithm, which is used for traversing tree or graph data structures, but it's not related to this problem.
Building a recursive solution
It makes sense to keep the recursive method to be void to avoid wrapping the result with an additional list that would be thrown away afterwards, but in general it's more handy to return the result rather than accumulating it in the parameter. For performance reasons, I'll keep the method to be void.
Every recursive implementation should contain two parts:
Base case - that represents a simple edge-case (or a set of edge-cases) for which the outcome is known in advance. For this problem the base case would represent a situation when the given permutation has reached the size of the initial array, i.e. the source will contain no element, and we need to check whether it's empty or not. Parameters cs and ts that were used for this check in the solution provided in the question are redundant.
Recursive case - a part of a solution where recursive calls a made and when the main logic resides. In the recursive case, we need to replicate the given answer and source as explained above and use the updated copies as the arguments for each recursive call.
That's how it might be implemented:
public static List<List<Integer>> permute(int[] nums) {
Set<Integer> source = new LinkedHashSet<>();
for (int next: nums) source.add(next);
List<List<Integer>> result = new ArrayList<>();
permute(source, new ArrayList<>(), result);
return result;
}
public static void permute(Set<Integer> source, List<Integer> answer,
List<List<Integer>> result) {
if (source.isEmpty()) {
result.add(answer);
return;
}
for (Integer next: source) {
List<Integer> updatedAnswer = new ArrayList<>(answer);
updatedAnswer.add(next);
Set<Integer> updatedSource = new LinkedHashSet<>(source);
updatedSource.remove(next);
permute(updatedSource, updatedAnswer, result);
}
}
main()
public static void main(String[] args) {
int[] source = {1, 2, 3};
List<List<Integer>> permutations = permute(source);
for (List<Integer> permutation: permutations) {
System.out.println(permutation);
}
}
Output:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
A link to Online Demo
I need to provide a Java solution that given two list, a & b, that returns a value that is present in one list but not in another.
e.g.
lists a = [26, 13, 88, 9]
lists b = [26, 1, 8, 12]
for those kind of operation it would be better to use collections,
the method removeAll() will filter the data containers, from the doc:
Removes from this list all of its elements that are contained in the
specified collection (optional operation).
List<Integer> myVarListA = Arrays.asList(26, 13, 88, 9);
List<Integer> myVarListB = Arrays.asList(26, 1, 8, 12);
List<Integer> myVarListAcomplementB = new ArrayList<>(myVarListA);
List<Integer> myVarListBcomplementA = new ArrayList<>(myVarListB);
myVarListAcomplementB.removeAll(myVarListB);
myVarListBcomplementA.removeAll(myVarListA);
System.out.println("elements in A but no in B: " + myVarListAcomplementB);
System.out.println("elements in B but no in A: " + myVarListBcomplementA);
myVarListBcomplementA.addAll(myVarListAcomplementB);
System.out.println("both together: " + myVarListBcomplementA);
Simple solution is to calculate the intersection and remove that from the desired list. If you only want what is missing, you can optimize this a little by going a solution like ΦXocę 웃 Пepeúpa ツ.
The great thing about this solution is that you can easily expand this to use 3+ sets/lists. Instead of A-B = diff or A-I(A,B)=diff, you can also do A-I(A,I(B,C)) to find what A is missing from the common set between A, B and C.
public static <T> HashSet<T> intersection(Collection<T> a, Collection<T> b) {
HashSet<T> aMinusB = new HashSet<>(a);
aMinusB.removeAll(b);
HashSet<T> common = new HashSet<>(a);
common.removeAll(aMinusB);
return common;
}
Let's call the intersection set Collection I = intersection(a,b);.
Now if you want to find what is missing from list A that was in B:
new LinkedList(A).removeAll(I);//ordered and possibly containing duplicates
OR
new ArrayList(A).removeAll(I);//ordered and possibly containing duplicates. Faster copy time, but slower to remove elements. Experiment with this and LinkedList for speed.
OR
new LinkedHashSet<T>(a).removeAll(I);//ordered and unique
OR
new HashSet<T>(a).removeAll(I);//unique and no order
Also, this question is effectively duplicate of How to do union, intersect, difference and reverse data in java
You may try this:
a.removeAll(b);
Simply parse the second list and add unique elements to the first, delete others.
for (Integer elem : secondList)
if (firstList.contains(elem))
firstList.remove(elem);
else
firstList.add(elem);
In firstList you will have the values present only in one of the lists.
i have two arraylist one have employee entity list other also have same entity list.
one Arraylist have all employees and other one have selected employees.
now i want to arrange employee in list in first Arraylist as on selected employees first arrive which is in second arraylist.
for Ex::
list1 [{1,test1}{2,test2},{3,test3},{4,test4}]
list2[{2,test2}{4,test4}]
what i want is
list1[{2,test2}{4,test4}{1,test1}{3,test3}]
How can i do this same by using single method or minimal line code ..
From what you have said it seems like you just need to take the members of list1 that are not in list2 and append them to list2 in the order they appear in list1.
Something like:
for ( Employee e : list1 ) {
if ( !list2.contains(e) ) {
list2.append(e);
}
}
Why not use Collections.sort(list1, yourComparator) where yourComparator sorts the entries in list1 as you need?
You could use Apache CollectionUtils like this:
CollectionUtils.addAll(list2, CollectionUtils.subtract(list1, list2));
You don't even need a loop or a comparator. Just use the Collections API!
Firstly, you want a LinkedHashSet - preserves uniqueness and order
Use the API to add list2, then list2, then populate a list with the set:
Here's an example using Integers:
// Set up your data
List<Integer> l1 = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
List<Integer> l2 = new ArrayList<Integer>(Arrays.asList(2, 5));
// Here's the 3 lines that do the work
Set<Integer> set = new LinkedHashSet<Integer>(l2);
set.addAll(l1);
List<Integer> l3 = new ArrayList<Integer>(set);
// All done
System.out.println(l3); // "[2, 5, 1, 3, 4]"
Let's say I have a list (EG: LinkedList<SomeObject>that contains elements ordered by a certain attribute (EG: SomeObject.someValue()). This attribute can and usually does repeat often/it isn't unique, BUT is never null.
Is there a convenient way to divide this into multiple Lists, each list containing only its equal in cardinal order? Also, can this be done with only once iteration of the list? For example, the original list:
1, 1, 1, 2, 2, 3, 3, 3
The desired lists from this:
1, 1, 1
2, 2,
3, 3, 3
Not too convenient, but:
start a loop. Store the previous item, and compare it to the current.
if the previous is different from the current (using equals(..), and be careful with null), then create a new List, or use list.subList(groupStart, currentIdx)
You could use Apache CollectionUtils to do this, where "list" is the original list, and "value" is the current value of the objects you want to extract a sublist for:
Collection<SomeObject> selectedObjects = CollectionUtils
.select(list,
new Predicate() {
boolean evaluate(Object input) {
return ((SomeObject) input).someValue().equals(value);
}
});
This approach means using a well known and well tested library (which always is a good thing), but the downside is that you will loop through the list once for each sublist you need.
Pretty sure there isn't a java API method for this. However you can write:
// This assumes your list is sorted according to someValue()
// SomeValueType is the type of SomeObject.someValue()
public Map<SomeValueType, List<SomeObject>> partition(List<SomeObject> list) {
Object currValue = null;
HashMap<SomeValueType, LinkedList<SomeObject>> result = new HashMap<SomeValueType, LinkedList<SomeObject>>();
LinkedList<SomeObject> currList = null;
for (SomeObject obj : list) {
if (!obj.someValue().equals(currValue()) {
currValue = obj.someValue();
currList = new LinkedList<SomeObject>();
result.put(currValue, currList);
}
currList.add(obj);
}
}
This will return you an HashMap of sublists, where the key is the someValue and the value is the partitioned list associated to it. Note, I didn't test this, so don't just copy the code.
EDIT: made this return hashmap instead of arraylist.
If you would use Google Guava-libaries:
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
public class Example {
public static void main(String[] args) {
HashMultiset<Integer> ints = HashMultiset.create();
ints.addAll(Lists.newArrayList(1, 1, 1, 2, 2, 3, 3, 3));
System.out.println(ints);
}
}
Output:
[1 x 3, 2 x 2, 3 x 3]
If you need to count how many elements of x you have use ints.count(x);, if you have value types you do not need to have more then just count.
With Guava, use Multimaps.index(Iterable<V>, Function<? super V, K>).
This should work (untested, but I am pretty sure everything is ok, This also assumes that the contents of the list are sortable):
public static List[] getEquivalentSubLists( List parent )
{
List cloneList = parent.clone();
Collections.sort(cloneList);
ArrayList<List> returnLists;
int end;
while (cloneList.size() > 0)
{
end = cloneList.lastIndexOf(cloneList.get(0));
returnLists.add(cloneList.subList(0, end));
cloneList.removeAll(cloneList.subList(0, end));
}
return returnList.toArray();
}
I have an ArrayList and I want to copy it exactly. I use utility classes when possible on the assumption that someone spent some time making it correct. So naturally, I end up with the Collections class which contains a copy method.
Suppose I have the following:
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b,a);
This fails because basically it thinks b isn't big enough to hold a. Yes I know b has size 0, but it should be big enough now shouldn't it? If I have to fill b first, then Collections.copy() becomes a completely useless function in my mind. So, except for programming a copy function (which I'm going to do now) is there a proper way to do this?
b has a capacity of 3, but a size of 0. The fact that ArrayList has some sort of buffer capacity is an implementation detail - it's not part of the List interface, so Collections.copy(List, List) doesn't use it. It would be ugly for it to special-case ArrayList.
As tddmonkey has indicated, using the ArrayList constructor which takes a collection is the way to in the example provided.
For more complicated scenarios (which may well include your real code), you may find the collections within Guava useful.
Calling
List<String> b = new ArrayList<String>(a);
creates a shallow copy of a within b. All elements will exist within b in the exact same order that they were within a (assuming it had an order).
Similarly, calling
// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);
also creates a shallow copy of a within b. If the first parameter, b, does not have enough capacity (not size) to contain all of a's elements, then it will throw an IndexOutOfBoundsException. The expectation is that no allocations will be required by Collections.copy to work, and if any are, then it throws that exception. It's an optimization to require the copied collection to be preallocated (b), but I generally do not think that the feature is worth it due to the required checks given the constructor-based alternatives like the one shown above that have no weird side effects.
To create a deep copy, the List, via either mechanism, would have to have intricate knowledge of the underlying type. In the case of Strings, which are immutable in Java (and .NET for that matter), you don't even need a deep copy. In the case of MySpecialObject, you need to know how to make a deep copy of it and that is not a generic operation.
Note: The originally accepted answer was the top result for Collections.copy in Google, and it was flat out wrong as pointed out in the comments.
Just do:
List a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
List b = new ArrayList(a);
ArrayList has a constructor that will accept another Collection to copy the elements from
The answer by Stephen Katulka (accepted answer) is wrong (the second part).
It explains that Collections.copy(b, a); does a deep copy, which it does not. Both, new ArrayList(a); and Collections.copy(b, a); only do a shallow copy. The difference is, that the constructor allocates new memory, and copy(...) does not, which makes it suitable in cases where you can reuse arrays, as it has a performance advantage there.
The Java standard API tries to discourage the use of deep copies, as it would be bad if new coders would use this on a regular basis, which may also be one of the reason why clone() is not public by default.
The source code for Collections.copy(...) can be seen on line 552 at:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/Collections.java.htm
If you need a deep copy, you have to iterate over the items manually, using a for loop and clone() on each object.
the simplest way to copy a List is to pass it to the constructor of the new list:
List<String> b = new ArrayList<>(a);
b will be a shallow copy of a
Looking at the source of Collections.copy(List,List) (I'd never seen it before) it seems to be for coping the elements index by index. using List.set(int,E) thus element 0 will over write element 0 in the target list etc etc. Not particularly clear from the javadocs I'd have to admit.
List<String> a = new ArrayList<>(a);
a.add("foo");
b.add("bar");
List<String> b = new ArrayList<>(a); // shallow copy 'a'
// the following will all hold
assert a.get(0) == b.get(0);
assert a.get(1) == b.get(1);
assert a.equals(b);
assert a != b; // 'a' is not the same object as 'b'
List b = new ArrayList(a.size())
doesn't set the size. It sets the initial capacity (being how many elements it can fit in before it needs to resize). A simpler way of copying in this case is:
List b = new ArrayList(a);
As hoijui mentions. The selected answer from Stephen Katulka contains a comment about Collections.copy that is incorrect. The author probably accepted it because the first line of code was doing the copy that he wanted. The additional call to Collections.copy just copies again. (Resulting in the copy happening twice).
Here is code to prove it.
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a);
System.out.println("There should be no output after this line.");
// Note, b is already a shallow copy of a;
for (int i = 0; i < a.size(); i++) {
if (a.get(i) != b.get(i)) {
System.out.println("Oops, this was a deep copy."); // Note this is never called.
}
}
// Now use Collections.copy and note that b is still just a shallow copy of a
Collections.copy(b, a);
for (int i = 0; i < a.size(); i++) {
if (a.get(i) != b.get(i)) {
System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called.
}
}
// Now do a deep copy - requires you to explicitly copy each element
for (int i = 0; i < a.size(); i++) {
b.set(i, new String(a.get(i)));
}
// Now see that the elements are different in each
for (int i = 0; i < a.size(); i++) {
if (a.get(i) == b.get(i)) {
System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called.
}
}
}
Most answers here do not realize the problem, the user wants to have a COPY of the elements from first list to the second list, destination list elements are new objects and not reference to the elements of original list.
(means changing an element of second list should not change values for corresponding element of source list.)
For the mutable objects we cannot use ArrayList(Collection) constructor because it will simple refer to the original list element and will not copy.
You need to have a list cloner for each object when copying.
Why dont you just use addAll method:
List a = new ArrayList();
a.add("1");
a.add("abc");
List b = b.addAll(listA);
//b will be 1, abc
even if you have existing items in b or you want to pend some elements after it, such as:
List a = new ArrayList();
a.add("1");
a.add("abc");
List b = new ArrayList();
b.add("x");
b.addAll(listA);
b.add("Y");
//b will be x, 1, abc, Y
Strings can be deep copied with
List<String> b = new ArrayList<String>(a);
because they are immutable. Every other Object not --> you need to iterate and do a copy by yourself.
If you want to copy an ArrayList, copy it by using:
List b = new ArrayList();
b.add("aa");
b.add("bb");
List a = new ArrayList(b);
private List<Item> cloneItemList(final List<Item> items)
{
Item[] itemArray = new Item[items.size()];
itemArray = items.toArray(itemArray);
return Arrays.asList(itemArray);
}
Every other Object not --> you need to iterate and do a copy by yourself.
To avoid this implement Cloneable.
public class User implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String user;
private String password;
...
#Override
public Object clone() {
Object o = null;
try {
o = super.clone();
} catch(CloneNotSupportedException e) {
}
return o;
}
}
....
public static void main(String[] args) {
List<User> userList1 = new ArrayList<User>();
User user1 = new User();
user1.setUser("User1");
user1.setPassword("pass1");
...
User user2 = new User();
user2.setUser("User2");
user2.setPassword("pass2");
...
userList1 .add(user1);
userList1 .add(user2);
List<User> userList2 = new ArrayList<User>();
for(User u: userList1){
u.add((User)u.clone());
}
//With this you can avoid
/*
for(User u: userList1){
User tmp = new User();
tmp.setUser(u.getUser);
tmp.setPassword(u.getPassword);
...
u.add(tmp);
}
*/
}
The following output illustrates results of using copy constructor and Collections.copy():
Copy [1, 2, 3] to [1, 2, 3] using copy constructor.
Copy [1, 2, 3] to (smaller) [4, 5]
java.lang.IndexOutOfBoundsException: Source does not fit in dest
at java.util.Collections.copy(Collections.java:556)
at com.farenda.java.CollectionsCopy.copySourceToSmallerDest(CollectionsCopy.java:36)
at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:14)
Copy [1, 2] to (same size) [3, 4]
source: [1, 2]
destination: [1, 2]
Copy [1, 2] to (bigger) [3, 4, 5]
source: [1, 2]
destination: [1, 2, 5]
Copy [1, 2] to (unmodifiable) [4, 5]
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableList.set(Collections.java:1311)
at java.util.Collections.copy(Collections.java:561)
at com.farenda.java.CollectionsCopy.copyToUnmodifiableDest(CollectionsCopy.java:68)
at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:20)
The source of full program is here: Java List copy. But the output is enough to see how java.util.Collections.copy() behaves.
And if you are using google guava, the one line solution would be
List<String> b = Lists.newArrayList(a);
This creates a mutable array list instance.
With Java 8 being null-safe, you could use the following code.
List<String> b = Optional.ofNullable(a)
.map(list -> (List<String>) new ArrayList<>(list))
.orElseGet(Collections::emptyList);
Or using a collector
List<String> b = Optional.ofNullable(a)
.map(List::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList())
Copy isn't useless if you imagine the use case to copy some values into an existing collection. I.e. you want to overwrite existing elements instead of inserting.
An example: a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy(b) = [1,2,3,4,5,3,3,3,3,4,4,4]
However I'd expect a copy method that would take additional parameters for the start index of the source and target collection, as well as a parameter for count.
See Java BUG 6350752
To understand why Collections.copy() throws an IndexOutOfBoundsException although you've made the backing array of the destination list large enough (via the size() call on the sourceList), see the answer by Abhay Yadav in this related question:
How to copy a java.util.List into another java.util.List