With 2 ArrayList, I was wondering if the best way from transforming the 1st one into a "copy" of the second one is to go like
myFirstArray.clear();
myFirstArray.addAll(mySecondArray);
or
myFirstArray = mySecondArray.clone();
What are the main differences between those two method, which on is preferrable and is there another "easier" or "cleaner" solution. Thanks for any tips
EDIT : I use this copy for replacing an Array of item im currently working with the one where I store the item I'll work with in the next loop. At the end of the loop I replace my currentArrayList with my futurArrayList and I clear my futurArraylist in order to add new item in it (i hope its clear enough)
The first one replaces the content of the list by another content. The second one creates another ArrayList instance, leaving the previous one untouched.
If the list is referenced by some other object, and you want this other object to be untouched, use the second one. If you want the other object to also have the new content, use the first one.
If nothing else referenced the list, it doesn't matter much. The second one will reduce the memory used in case you replace the content of a huge list by a few elements.
In java, though clone is ‘intended’ to produce a copy of the same object it is not guaranteed.
Clone comes with lots of its and buts. So my first advice is to not depend on clones.
By default, java cloning is ‘field by field copy’ i.e. as the Object class does not have idea about the structure of class on which clone() method will be invoked. So, JVM when called for cloning, do following things:
If the class has only primitive data type members then a completely
new copy of the object will be created and the reference to the new
object copy will be returned.
If the class contains members of any class type then only the object
references to those members are copied and hence the member
references in both the original object as well as the cloned object
refer to the same object because of that cloned object changes are visible in original also.
Use that:
List<Object> first = ...
ArrayList<Object> second = new ArrayList<>(first);
I also suggest that you do not use clone() at all. It's better to use a copy constructor or some factory method. Take a look at here.
Of course in your case, with the ArrayList, it will work as expected, you will end up with a copy of the references.
Guava, guava, guava!
final List copied = ImmutableList.copyOf(originalList);
Related
In C#, I just got the need of having an immutable list, meaning that the list can not be changed.
Much like in Java's immutable list: https://www.geeksforgeeks.org/immutable-list-in-java/
From there:
If any attempt is made to add null element in List,
UnsupportedOperationException is thrown.
Now, with .NET (at least with Core 2.2) there is also an immutable list, documented here.
They say (emphasis mine):
When you add or remove items from an immutable list, a copy of the
original list is made with the items added or removed, and the
original list is unchanged.
So, this implementation basically allows changing the list (by getting a manipulated copy each time), as opposed to the java understanding, and what's more, it will mostly go undetected clogging memory.
What's the point in having an immutable list that supports add and remove methods in the first place?
The problem for me here is, that users of my code would get a list, immutable presumably, but out of neglectance would happily add items, which will never made it to the original "repository". This will cause confusion.
I guess the (only) way to go here, to forbid manipulation entirely, and make it clear to the code user, would be to use the IEnumerale interface?
What's the point in having an immutable list that supports add and
remove methods in the first place?
No one but to be conform with the List contract, the implementation even immutable will expose every List methods.
After you have two ways to cope with these modification methods : throwing an exception or guaranteeing the immutability by creating and returning a new List at each modification.
About :
I guess the (only) way to go here, to forbid manipulation entirely,
would be to use the IEnumerale interface?
Indeed, in Java you use Iterable (that is close enough) when you want to be able to manipulate a collection of things without a way to change it.
As alternative you can also use an array.
As you said: "a copy of the original list is made with the items added or removed, and the original list is unchanged.".
So you can add/remove elements and a new list is made with the changes. The original list is unchanged.
What's the point in having an immutable list that supports add and remove methods in the first place?
First think of this: What is the point of an immutable list that doesn't support adding or removing items in any way? There is nothing particular useful to that. You can use array for that.
Now back to your question. The list is immutable, so consumers can't change the instance itself which was provided through some other method or class. The backing storage can't be altered by consumers! But the producer of the immutable list can 'alter' the backing store by creating a new immutable list and assigning that to the original variable. Isn't that useful!
A class has a Set of String objects defined as its instance variable.
Step-1: I have a method which creates an object for this class, assign an empty set of String to the instance variable and then returns the object.
The method which receives it, passes it to another method which adds more String to that empty set.
Now how should I create the empty set in Step-1?
a. Using Collections.<String>emptyList() creates an immutable Set of strings and this isn't giving an error when new Strings are added later in the second method. Needed some details on the fundamentals on how this is happening.
b. new HashSet<>() This creates a mutable map.
Which is the right approach and why? Is there another good way?
It sounds from your question as if you are producing an instance via a builder, and then later somebody tries to modify the produced instance.
Don't write it like that; builders should virtually always return immutables. If during the build process no elements are added to the set, then Set.of() it is (or, in pre-JDK9 API, Collections.emptySet()). These will throw when you try to add to them, which is the point.
If your intent is to create a mutable object, via builder or no, obviously some mutable set is required then. Possibly HashSet, but note that HashSet is normally a bad idea with builders; the general expectation is that order is maintained, so you'd need LinkedHashSet instead, or, preferably, something like guava's ImmutableSet which is more optimized.
I have deep nested structures, and methods like "remove(<Something>)", "contains(<Something>)" etc. rely on access to the original reference in order to remove it etc. (a copy of the reference won't do).
How have people best worked around this so they can still conveniently add, remove, test for etc. the object they want, within different arbitrary methods and constructors etc., without adding any unnecessary complexity or any unnecessary loss in performance?
Methods like remove and contains work fine with pass by value. The reason is that the even though the references are copied, they copy has the same value of the original. Just look at the Collections API. If you do something like (psuedocode)
List list = new List();
list.add(object1) // assume you have an object1 reference
and then you do
myRemove(list, object1);
both list and object 1 are passed by value, so in the myRemove method they are copies of the original reference. If in myRemove you do
list.remove(object1);
the object is still removed from the list no problem. Furthermore, since the list and object1 references in both scopes point to the same underlying objects, the list reference in the calling scope refers to the list that has the object removed.
The only time you would need pass by reference semantics is if you want to modify a reference in a method and have the modification apply in the scope that called the method.
So if you want to do
List myList = new List();
changeList(myList);
and have changeList change where myList points in the calling scope, it wont work without some trickery. The trickery is called double indirection. Basically, you create an object that has an instance of what you want to be able to access with pass by reference semantics, and you pass the container object around.
So
class MyContainer {
List list
}
now you can pass an instance of MyContainer into a method, and change the list value, and in the calling scope where the list points will be changed. Note that you are not doing anything special here, everything is still pass by value.
How have people best worked around this so...
By use of member fields (for working with references, not copies) and by use of inheritance and interfaces (for handling nested structures).
For example I have a reference to an mItem object of my List<mItem> mList collection. Is that possible to get a reference to mList using mItem?
The short answer is no. The items in a list don't know they are in a list. (Unless of course you add a reference to the list inside your mItem object.)
Short answer: no.
Adding an item to a list adds a reference to that object to the list. It does not affect the object itself.
You can check to see if an item is in a specific list, with mList.contains(mItem) which returns true if the item is in mList. Alternatively if you really need to, you could as others have suggested implement a version of List that informs each item that the list has a reference to that item. The overhead would be rather messy though.
Meta question: why do you need this functionality?
As jzd said... you can add a field to your mItem class (for example referenceHolder)
mItem(Object ref){
referenceHolder = ref;
}
class with List:
mList.add(new mItem(this));
something like that should work :) but its kind of weird ;), because normally "The items in a list don't know they are in a list. "
EDIT: and as said before - "One object should be a member of multiple collections" - so you would need to change type of my referenceHolder to some list or array, to make that able to happen.
EDIT2: that's just reference to object holding that list (if one object will have multiple lists, you wont be able to know witch of them is holding that sepecified mItem object), to reference to List itself you will need (as said in comment ;)) custom list implementation adding references to stored objects with this in add() method.
If you have a container for all you lists, you can call contains on each one to find which list the item is in.
Note: for a list you can have the same element multiple time, and across multiple list.
BTW: If you don't want duplicates in a list and don't care about the order of elements then a Set may be your best choice.
Pretty self explanatory: I need to modify the ArrayList that I receive, but I want the original to be unchanged.
I know this is very basic, and I'm not sure why I don't know the definitive answer. I guess better late than never though.
You will have a reference to the original ArrayList.
You can create a shallow copy of the list with clone().
Have a look at this question if you want a deep copy.
Everything in java will be a reference by default. So yes changing the returned arraylist will modify the original one.
To prevent that problem you have to create a copy of the original one. Use the .clone() method for that.
If you want a modified list, but not to modify the original, you shouldn't operate on the list which you received in arguments of the method because you operate on reference. Better use something like this:
public void modifyList(List myList) {
myList.add("aaa"); // original *will* be modified
List modifiable = new ArrayList(myList);
modifiable.add("bbb"); // original will *not* be modified - only the copy
}
It will be the same ArrayList. If you want a copy, you'll have to copy it yourself. Not necessarily easy if the ArrayList holds complex objects!
I think java is pass-by-value always.
The only thing to remember is that objects are passed by passing the value of their address, or reference to them, this makes it seem as if they are passed by reference in C++ terms. Because essentially, you are passing the reference address not a copy of the object. The address is passed by value.
Thus, Java can say it is always passed by value because even when it is passing an object, it is only passing the value of its memory reference on the heap stack, not a clone/copy of the target object.
An Arraylist is an object, therefore it will be passed by value, so the value passed in will be a reference to the original Arraylist on the heap. Any modification to the Arraylist in your function, will modify the original on the heap.
I have not used the .clone(). I leave that to others to help with. Meanwhile, I will go learn about them myself.