Before you doing anything make sure you've read and understood the discussion here: Java benchmarking - why is the second loop faster?
I would expect addAll to be faster in some situations as it has more information to work with.
For example on an ArrayList addAll can make sure it allocates enough space to add every single element in one step, rather than having to reallocate multiple times if adding large numbers of elements.
It would certainly not be slower as even a naive implementation of it would just do what you do, loop through adding the items.
Answer from Tim B on Stack OverflowBefore you doing anything make sure you've read and understood the discussion here: Java benchmarking - why is the second loop faster?
I would expect addAll to be faster in some situations as it has more information to work with.
For example on an ArrayList addAll can make sure it allocates enough space to add every single element in one step, rather than having to reallocate multiple times if adding large numbers of elements.
It would certainly not be slower as even a naive implementation of it would just do what you do, loop through adding the items.
Check the implementation of the addAll method - nothing different that what you'd do - AbstractCollection code
Copy the cities set (to say, citiesCopy), and then call citiesCopy.retainAll(anotherCitiesSet) - the resulting set in citiesCopy will contain the intersection of the two sets, thus allowing you to easily see which cities are duplicated, if any.
Alternatively, loop through the second set and manually add each of the elements, checking the return value from add() each time:
for(java.util.Set<City> c : anotherCitiesSet) {
if(!cities.add(c)) {
// c was a duplicate, do something?
}
}
is your city just String (tho it is object) or it is object containing other stuffs?
if String, then I guess above answers will work.
if it is object containing things like : String name, int population, etc... And you only want to compare String name to remove duplicates, then you can use {HashSet} class and override its (HashCode) and (equals) methods.
because you may have two cities: NYC, and another NYC. containing the same info. but since they are two objects in heap. they will have different HashCode. There say, your HashSet will keep both of them. HashSet checks both HashCode and meaning equals().
The solution is to override both methods:
class City{
String name; //if you only care city name
....
....
public boolean equals(Object myCity){ // override equals(). only look at the name.
City city2 = (City) myCity;
return this.getName().equals(city2.getName()); //String itself has a .equal() to compare
}
public int HashCode(){ // override HashCode().
return name.hashCode(); //also String itself has a .hashCode() to check equality
}
public String getName(){
return name;
}
...
...
}
addAll basically iterates over the collection it's given and calls add on every method. Here's the way OpenJDK8 implements it:
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
But as a general rule of thumb, you shouldn't try to invent the wheel unless you're absolutely sure you can invent a better one.
Your question is incomplete. Let’s complete it with the actual alternatives.
First, you have a method which populates a provided Set:
void getSomedata(String param, Set<String> uniqueSet)
which has to be used like
Set<String> uniqueSet = new HashSet<String>();
getSomedata(param1, uniqueSet);
getSomedata(param2, uniqueSet);
The alternative is to have a method which returns a new Set:
Set<String> getSomedata(String param)
which you can use like
Set<String> uniqueSet = getSomedata(param1);
uniqueSet.addAll( getSomedata(param2) );
in this case, you are ignoring how the method getSomedata will create and populate the Set that it will return. Obviously, unless it creates a custom Set implementation projecting source data, it has to create a Set and populate it with elements before returning it.
In other words, it doesn’t matter, how addAll is implemented, at the time you are going to invoke it, this solution has already performed the same work as the other alternative, as it already has added all elements to a Set. So, even if addAll of a particular Set implementation has optimizations, it’s work adds to the already performed work of individually adding all elements to a Set.
Still, the rule that you shouldn’t worry about performance unless there is a real performance problem applies. The involved I/O might outweigh it all. Or the unpredictability of the effects of hotspot optimization and memory management might change it all. If you think, getSomedate returning a new Set is cleaner (that would be reasonable), use it.
As an addendum, I simplified a bit. A HashSet is O(1) only in theory, but will perform different when there are hash collisions and in the case TreeSets are used, which have O(log n) time complexity, the different size of the sets has an effect, thus the alternatives, operating on sets of different size, are not exactly comparable, depending on which Set implementations are used and other surrounding context. But the tendency is still the same, especially as in most cases, there are no optimized addAll implementations (EnumSet might be the only exception).
You can collect using addAll with a 3-argument collect:
Set<Integer> result = ll.stream()
.map(MyObject::getTheSet)
.collect(HashSet::new, Set::addAll, Set::addAll);
HashSet::new makes a new container, Set::addAll adds each set into the container, 2nd Set::addAll merges two containers if this stream were to be run in parallel.
(or use TreeSet::new if you specifically want a TreeSet)
Instead i think about something like .addAll or does it in the end not matter, because .addAll unpacks anyway?
TreeSet.addAll() has an optimized codepath for adding Collections that implement SortedSet assuming they have the same sort order.
Caveat: This is an undocumented implementation detail and thus subject to change.
You could easily have found this information yourself simply looking at the JDK source code, which is included in the src.zip shipped with the JDK.
I tried your code and it works for me.
One thing though - it would be better to use the generic versions of the collections. This removes the warnings.
List<Integer> a = new ArrayList<Integer>();
a.add(20);
List<Integer> b = new ArrayList<Integer>();
b.add(30);
Set<Integer> set = new HashSet<Integer>(a);
set.addAll(b);
This works fine, just that if you add a list to the set, the repeated elements between the list and the set are added just once.
Say for example ArrayList arr has elements 2,3,4 and HashSet set has elements 2,5,7 now if you do set.addAll(arr), then set still includes 2,5,7,3,4.
Also Imagine a scenario where you have an ArrayList arr and HashSet set where T is a generic class containing several parameters, then common elements in the final set will be removed as per equals method's overridden definition in T class and the element added to set will be persisted in the final set over the element in the arraylist.