How to get Map.values as a Set rather than a Collection? - java

I have a map Map<String, SomeType> where every instance of SomeType is added by name like map.put(object.getName(), object). In the end, there are no duplicates in map.values().
Now, I want a Set<SomeType> from this map without making a copy like new HashSet<>(map.values()).
Is this possible, preferential only with the standard library?

You already know how to do it with new HashSet<>(map.values()). You can't get a Set of the values directly, since the values can contain duplicates. Even if in your specific Map there are no duplicate values, in a general Map there can be duplicate values.
You can do something with Java 8 Streams, but it has no advantage over instantiating the Set explicitly.
Set<SomeType> values = map.values().stream().collect(Collectors.toSet());

Without a Collection wrapper it is not possible.
Just because in your case there are no duplications, that does not mean they cannot be.
Java Collections API allow you to put duplicate values in the Map, so the contract has to return Collection and not Set.

It would be a simple matter to create a Set view of any Collection.
public final class SetView<E> extends AbstractSet<E> {
private final Collection<? extends E> collection;
private SetView(Collection<? extends E> collection) {
this.collection = collection;
}
public static <E> SetView<E> of(Collection<? extends E> collection) {
return new SetView<>(collection);
}
#Override
public boolean contains(Object e) {
return collection.contains(e);
}
// rest omitted.
}
With this, you could then write Set<E> set = SetView.of(map.values()); and all changes to the Map would automatically be reflected in the Set.
The problem with this approach is that some methods would be difficult to implement without copying the Collection. For example, how would you write size()?
The most sensible way is
#Override
public int size() {
return new HashSet<>(collection).size();
}
but this defeats the purpose of using a view rather than just copying the elements in the first place. If you know that the Collection will never contain duplicates, you could simply do
#Override
public int size() {
return collection.size();
}
However I would advise against such an approach. A Map is allowed to contain duplicate values, and the possibility of adding two entries with the same value means that the contract for Set would be broken.
Unless you have very good reason for not wanting to copy the elements, I would just use new HashSet<>(map.values()).

Related

Accessing an element in a Set [duplicate]

Why doesn't Set provide an operation to get an element that equals another element?
Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo); // get the Foo element from the Set that equals foo
I can ask whether the Set contains an element equal to bar, so why can't I get that element? :(
To clarify, the equals method is overridden, but it only checks one of the fields, not all. So two Foo objects that are considered equal can actually have different values, that's why I can't just use foo.
To answer the precise question "Why doesn't Set provide an operation to get an element that equals another element?", the answer would be: because the designers of the collection framework were not very forward looking. They didn't anticipate your very legitimate use case, naively tried to "model the mathematical set abstraction" (from the javadoc) and simply forgot to add the useful get() method.
Now to the implied question "how do you get the element then": I think the best solution is to use a Map<E,E> instead of a Set<E>, to map the elements to themselves. In that way, you can efficiently retrieve an element from the "set", because the get() method of the Map will find the element using an efficient hash table or tree algorithm. If you wanted, you could write your own implementation of Set that offers the additional get() method, encapsulating the Map.
The following answers are in my opinion bad or wrong:
"You don't need to get the element, because you already have an equal object": the assertion is wrong, as you already showed in the question. Two objects that are equal still can have different state that is not relevant to the object equality. The goal is to get access to this state of the element contained in the Set, not the state of the object used as a "query".
"You have no other option but to use the iterator": that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the Set is organized as hash map or tree that could be queried efficiently). Don't do it! I have seen severe performance problems in real-life systems by using that approach. In my opinion what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.
There would be no point of getting the element if it is equal. A Map is better suited for this usecase.
If you still want to find the element you have no other option but to use the iterator:
public static void main(String[] args) {
Set<Foo> set = new HashSet<Foo>();
set.add(new Foo("Hello"));
for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
Foo f = it.next();
if (f.equals(new Foo("Hello")))
System.out.println("foo found");
}
}
static class Foo {
String string;
Foo(String string) {
this.string = string;
}
#Override
public int hashCode() {
return string.hashCode();
}
#Override
public boolean equals(Object obj) {
return string.equals(((Foo) obj).string);
}
}
If you have an equal object, why do you need the one from the set? If it is "equal" only by a key, an Map would be a better choice.
Anyway, the following will do it:
Foo getEqual(Foo sample, Set<Foo> all) {
for (Foo one : all) {
if (one.equals(sample)) {
return one;
}
}
return null;
}
With Java 8 this can become a one liner:
return all.stream().filter(sample::equals).findAny().orElse(null);
Default Set in Java is, unfortunately, not designed to provide a "get" operation, as jschreiner accurately explained.
The solutions of using an iterator to find the element of interest (suggested by dacwe) or to remove the element and re-add it with its values updated (suggested by KyleM), could work, but can be very inefficient.
Overriding the implementation of equals so that non-equal objects are "equal", as stated correctly by David Ogren, can easily cause maintenance problems.
And using a Map as an explicit replacement (as suggested by many), imho, makes the code less elegant.
If the goal is to get access to the original instance of the element contained in the set (hope I understood correctly your use case), here is another possible solution.
I personally had your same need while developing a client-server videogame with Java. In my case, each client had copies of the components stored in the server and the problem was whenever a client needed to modify an object of the server.
Passing an object through the internet meant that the client had different instances of that object anyway. In order to match this "copied" instance with the original one, I decided to use Java UUIDs.
So I created an abstract class UniqueItem, which automatically gives a random unique id to each instance of its subclasses.
This UUID is shared between the client and the server instance, so this way it could be easy to match them by simply using a Map.
However directly using a Map in a similar usecase was still inelegant. Someone might argue that using an Map might be more complicated to mantain and handle.
For these reasons I implemented a library called MagicSet, that makes the usage of an Map "transparent" to the developer.
https://github.com/ricpacca/magicset
Like the original Java HashSet, a MagicHashSet (which is one of the implementations of MagicSet provided in the library) uses a backing HashMap, but instead of having elements as keys and a dummy value as values, it uses the UUID of the element as key and the element itself as value. This does not cause overhead in the memory use compared to a normal HashSet.
Moreover, a MagicSet can be used exactly as a Set, but with some more methods providing additional functionalities, like getFromId(), popFromId(), removeFromId(), etc.
The only requirement to use it is that any element that you want to store in a MagicSet needs to extend the abstract class UniqueItem.
Here is a code example, imagining to retrieve the original instance of a city from a MagicSet, given another instance of that city with the same UUID (or even just its UUID).
class City extends UniqueItem {
// Somewhere in this class
public void doSomething() {
// Whatever
}
}
public class GameMap {
private MagicSet<City> cities;
public GameMap(Collection<City> cities) {
cities = new MagicHashSet<>(cities);
}
/*
* cityId is the UUID of the city you want to retrieve.
* If you have a copied instance of that city, you can simply
* call copiedCity.getId() and pass the return value to this method.
*/
public void doSomethingInCity(UUID cityId) {
City city = cities.getFromId(cityId);
city.doSomething();
}
// Other methods can be called on a MagicSet too
}
If your set is in fact a NavigableSet<Foo> (such as a TreeSet), and Foo implements Comparable<Foo>, you can use
Foo bar = set.floor(foo); // or .ceiling
if (foo.equals(bar)) {
// use bar…
}
(Thanks to #eliran-malka’s comment for the hint.)
With Java 8 you can do:
Foo foo = set.stream().filter(item->item.equals(theItemYouAreLookingFor)).findFirst().get();
But be careful, .get() throws a NoSuchElementException, or you can manipulate a Optional item.
Convert set to list, and then use get method of list
Set<Foo> set = ...;
List<Foo> list = new ArrayList<Foo>(set);
Foo obj = list.get(0);
Why:
It seems that Set plays a useful role in providing a means of comparison. It is designed not to store duplicate elements.
Because of this intention/design, if one were to get() a reference to the stored object, then mutate it, it is possible that the design intentions of Set could be thwarted and could cause unexpected behavior.
From the JavaDocs
Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.
How:
Now that Streams have been introduced one can do the following
mySet.stream()
.filter(object -> object.property.equals(myProperty))
.findFirst().get();
Object objectToGet = ...
Map<Object, Object> map = new HashMap<Object, Object>(set.size());
for (Object o : set) {
map.put(o, o);
}
Object objectFromSet = map.get(objectToGet);
If you only do one get this will not be very performing because you will loop over all your elements but when performing multiple retrieves on a big set you will notice the difference.
you can use Iterator class
import java.util.Iterator;
import java.util.HashSet;
public class MyClass {
public static void main(String[ ] args) {
HashSet<String> animals = new HashSet<String>();
animals.add("fox");
animals.add("cat");
animals.add("dog");
animals.add("rabbit");
Iterator<String> it = animals.iterator();
while(it.hasNext()) {
String value = it.next();
System.out.println(value);
}
}
}
it looks like the proper object to use is the Interner from guava :
Provides equivalent behavior to String.intern() for other immutable
types. Common implementations are available from the Interners
class.
It also has a few very interesting levers, like concurrencyLevel, or the type of references used (it might be worth noting that it doesn't offer a SoftInterner which I could see as more useful than a WeakInterner).
I know, this has been asked and answered long ago, however if anyone is interested, here is my solution - custom set class backed by HashMap:
http://pastebin.com/Qv6S91n9
You can easily implement all other Set methods.
Been there done that!! If you are using Guava a quick way to convert it to a map is:
Map<Integer,Foo> map = Maps.uniqueIndex(fooSet, Foo::getKey);
If you want nth Element from HashSet, you can go with below solution,
here i have added object of ModelClass in HashSet.
ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
m1 = (ModelClass) itr.next();
if(nth == index) {
System.out.println(m1);
break;
}
}
If you look at the first few lines of the implementation of java.util.HashSet you will see:
public class HashSet<E>
....
private transient HashMap<E,Object> map;
So HashSet uses HashMap interally anyway, which means that if you just use a HashMap directly and use the same value as the key and the value you will get the effect you want and save yourself some memory.
Because any particular implementation of Set may or may not be random access.
You can always get an iterator and step through the Set, using the iterators' next() method to return the result you want once you find the equal element. This works regardless of the implementation. If the implementation is NOT random access (picture a linked-list backed Set), a get(E element) method in the interface would be deceptive, since it would have to iterate the collection to find the element to return, and a get(E element) would seem to imply this would be necessary, that the Set could jump directly to the element to get.
contains() may or may not have to do the same thing, of course, depending on the implementation, but the name doesn't seem to lend itself to the same sort of misunderstandings.
Yes, use HashMap ... but in a specialised way: the trap I foresee in trying to use a HashMap as a pseudo-Set is the possible confusion between "actual" elements of the Map/Set, and "candidate" elements, i.e. elements used to test whether an equal element is already present. This is far from foolproof, but nudges you away from the trap:
class SelfMappingHashMap<V> extends HashMap<V, V>{
#Override
public String toString(){
// otherwise you get lots of "... object1=object1, object2=object2..." stuff
return keySet().toString();
}
#Override
public V get( Object key ){
throw new UnsupportedOperationException( "use tryToGetRealFromCandidate()");
}
#Override
public V put( V key, V value ){
// thorny issue here: if you were indavertently to `put`
// a "candidate instance" with the element already in the `Map/Set`:
// these will obviously be considered equivalent
assert key.equals( value );
return super.put( key, value );
}
public V tryToGetRealFromCandidate( V key ){
return super.get(key);
}
}
Then do this:
SelfMappingHashMap<SomeClass> selfMap = new SelfMappingHashMap<SomeClass>();
...
SomeClass candidate = new SomeClass();
if( selfMap.contains( candidate ) ){
SomeClass realThing = selfMap.tryToGetRealFromCandidate( candidate );
...
realThing.useInSomeWay()...
}
But... you now want the candidate to self-destruct in some way unless the programmer actually immediately puts it in the Map/Set... you'd want contains to "taint" the candidate so that any use of it unless it joins the Map makes it "anathema". Perhaps you could make SomeClass implement a new Taintable interface.
A more satisfactory solution is a GettableSet, as below. However, for this to work you have either to be in charge of the design of SomeClass in order to make all constructors non-visible (or... able and willing to design and use a wrapper class for it):
public interface NoVisibleConstructor {
// again, this is a "nudge" technique, in the sense that there is no known method of
// making an interface enforce "no visible constructor" in its implementing classes
// - of course when Java finally implements full multiple inheritance some reflection
// technique might be used...
NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet );
};
public interface GettableSet<V extends NoVisibleConstructor> extends Set<V> {
V getGenuineFromImpostor( V impostor ); // see below for naming
}
Implementation:
public class GettableHashSet<V extends NoVisibleConstructor> implements GettableSet<V> {
private Map<V, V> map = new HashMap<V, V>();
#Override
public V getGenuineFromImpostor(V impostor ) {
return map.get( impostor );
}
#Override
public int size() {
return map.size();
}
#Override
public boolean contains(Object o) {
return map.containsKey( o );
}
#Override
public boolean add(V e) {
assert e != null;
V result = map.put( e, e );
return result != null;
}
#Override
public boolean remove(Object o) {
V result = map.remove( o );
return result != null;
}
#Override
public boolean addAll(Collection<? extends V> c) {
// for example:
throw new UnsupportedOperationException();
}
#Override
public void clear() {
map.clear();
}
// implement the other methods from Set ...
}
Your NoVisibleConstructor classes then look like this:
class SomeClass implements NoVisibleConstructor {
private SomeClass( Object param1, Object param2 ){
// ...
}
static SomeClass getOrCreate( GettableSet<SomeClass> gettableSet, Object param1, Object param2 ) {
SomeClass candidate = new SomeClass( param1, param2 );
if (gettableSet.contains(candidate)) {
// obviously this then means that the candidate "fails" (or is revealed
// to be an "impostor" if you will). Return the existing element:
return gettableSet.getGenuineFromImpostor(candidate);
}
gettableSet.add( candidate );
return candidate;
}
#Override
public NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet ){
// more elegant implementation-hiding: see below
}
}
PS one technical issue with such a NoVisibleConstructor class: it may be objected that such a class is inherently final, which may be undesirable. Actually you could always add a dummy parameterless protected constructor:
protected SomeClass(){
throw new UnsupportedOperationException();
}
... which would at least let a subclass compile. You'd then have to think about whether you need to include another getOrCreate() factory method in the subclass.
Final step is an abstract base class (NB "element" for a list, "member" for a set) like this for your set members (when possible - again, scope for using a wrapper class where the class is not under your control, or already has a base class, etc.), for maximum implementation-hiding:
public abstract class AbstractSetMember implements NoVisibleConstructor {
#Override
public NoVisibleConstructor
addOrGetExisting(GettableSet<? extends NoVisibleConstructor> gettableSet) {
AbstractSetMember member = this;
#SuppressWarnings("unchecked") // unavoidable!
GettableSet<AbstractSetMembers> set = (GettableSet<AbstractSetMember>) gettableSet;
if (gettableSet.contains( member )) {
member = set.getGenuineFromImpostor( member );
cleanUpAfterFindingGenuine( set );
} else {
addNewToSet( set );
}
return member;
}
abstract public void addNewToSet(GettableSet<? extends AbstractSetMember> gettableSet );
abstract public void cleanUpAfterFindingGenuine(GettableSet<? extends AbstractSetMember> gettableSet );
}
... usage is fairly obvious (inside your SomeClass's static factory method):
SomeClass setMember = new SomeClass( param1, param2 ).addOrGetExisting( set );
The contract of the hash code makes clear that:
"If two objects are equal according to the Object method, then calling the hashCode method on each of the two objects must produce the same integer result."
So your assumption:
"To clarify, the equals method is overridden, but it only checks one of
the fields, not all. So two Foo objects that are considered equal can
actually have different values, that's why I can't just use foo."
is wrong and you are breaking the contract. If we look at the "contains" method of Set interface, we have that:
boolean contains(Object o);
Returns true if this set contains the specified element. More
formally, returns true if and only if this set contains an element
"e" such that o==null ? e==null : o.equals(e)
To accomplish what you want, you can use a Map where you define the key and store your element with the key that defines how objects are different or equal to each other.
Here's what you can do if you have a NavigableSet (e.g. a TreeSet):
public static <E> E get(NavigableSet<E> set, E key) {
return set.tailSet(key, true).floor(key);
}
The things are slightly trickier for HashSet and its descendants like LinkedHashSet:
import java.util.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
private static final Field mapField;
private static final Method hashMethod;
private static final Method getNodeMethod;
private static final Field keyField;
static {
try {
mapField = HashSet.class.getDeclaredField("map");
mapField.setAccessible(true);
hashMethod = HashMap.class.getDeclaredMethod("hash", Object.class);
hashMethod.setAccessible(true);
getNodeMethod = HashMap.class.getDeclaredMethod("getNode",
Integer.TYPE, Object.class);
getNodeMethod.setAccessible(true);
keyField = Class.forName("java.util.HashMap$Node").getDeclaredField("key");
keyField.setAccessible(true);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static <E> E get(HashSet<E> set, E key) {
try {
Object map = mapField.get(set);
Object hash = hashMethod.invoke(null, key);
Object node = getNodeMethod.invoke(map, hash, key);
if (node == null)
return null;
#SuppressWarnings("unchecked")
E result = (E)keyField.get(node);
return result;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static <E> E get(NavigableSet<E> set, E key) {
return set.tailSet(key, true).floor(key);
}
public static void main(String[] args) {
HashSet<Integer> s = new HashSet<>();
// HashSet<Integer> s = new LinkedHashSet<>();
// TreeSet<Integer> s = new TreeSet<>();
for (int i = 0; i < 100_000; i++)
s.add(i);
Integer key = java.awt.event.KeyEvent.VK_FIND;
Integer hidden = get(s, key);
System.out.println(key);
System.out.println(hidden);
System.out.println(key.equals(hidden));
System.out.println(key == hidden);
}
}
Quick helper method that might address this situation:
<T> T onlyItem(Collection<T> items) {
if (items.size() != 1)
throw new IllegalArgumentException("Collection must have single item; instead it has " + items.size());
return items.iterator().next();
}
Try using an array:
ObjectClass[] arrayName = SetOfObjects.toArray(new ObjectClass[setOfObjects.size()]);
Following can be an approach
SharedPreferences se_get = getSharedPreferences("points",MODE_PRIVATE);
Set<String> main = se_get.getStringSet("mydata",null);
for(int jk = 0 ; jk < main.size();jk++)
{
Log.i("data",String.valueOf(main.toArray()[jk]));
}

How to return collections' data without returning a collection itself?

I have a class (A.java) that contains two private fields of type ArrayList and HashMap.
I also have another class (B.java) that should have access to their data. I could make two getters, but I don't want to return my collections as is. Class B.java should only have access to data, not to add(), isEmpty(), containsKey() etc.
Can I return my collections in such way, so I could somehow use it with foreach in class B somehow but without giving the possibility to modify them?
Don't return a collection, return a Stream. That way it is easy for the user to know that they are getting a stream of objects, not a collection. And it's easy to change the implementation of the collection without changing the way it's used. It's trivial for the user to filter, map, reduce collect etc.
So:
class A {
private List<C> cs = new ArrayList<>();
public Stream<C> getCs() {
return cs.stream();
}
}
class B {
public void processCs(A a) {
a.getCs().filter(C::hasFooness).forEach(...);
}
}
Create a getter method that returns a "Collections.unmodifiableList()" like this:
List<String> strings = new ArrayList<String>();
List<String> unmodifiable = Collections.unmodifiableList(strings);
unmodifiable.add("New string"); // will fail at runtime
strings.add("Aha!"); // will succeed
System.out.println(unmodifiable);

Which is good practice - Modifying a List in the method, or returning a new List in the method?

Example code:
modifyMyList(myList);
public void modifyMyList(List someList){
someList.add(someObject);
}
or:
List myList = modifyMyList(myList);
public List modifyMyList(List someList){
someList.add(someObject)
return someList;
}
There is also a 3rd option I believe: You can create a new List in modifyMyList method and return this new List...
( 3rd option is here, I was too lazy but someone already added it in the answers: )
List myList = modifyMyList(myList);
public List modifyMyList(List someList){
List returnList = new ArrayList();
returnList.addAll(someList);
returnList.add(someObject);
return Collections.unmodifiableList(returnList);
}
Is there any reason why I should choose one over another? What should be considered in such case?
I have a (self imposed) rule which is "Never mutate a method parameter in a public method". So, in a private method, it's ok to mutate a parameter (I even try to avoid this case too). But when calling a public method, the parameters should never be mutated and should be considered immutable.
I think that mutating method arguments is a bit hacky and can lead to bugs that are harder to see.
I have been known to make exceptions to this rule but I need a really good reason.
Actually there is no functional difference.
You'll come to know the difference when you want the returned list
List someNewList = someInstnace.modifyMyList(list);
The second is probably confusing as it implies a new value is being created and returned - and it isn't.
An exception would be if the method was part of a 'fluent' API, where the method was an instance method and was modifying its instance, and then returning the instance to allow method chaining: the Java StringBuilder class is an example of this.
In general, however, I wouldn't use either.
I'd go for your third option: I write a method that creates and returns a new list with the appropriate change. This is a bit artificial in the case of your example, as the example is really just reproducing List.add(), but...
/** Creates a copy of the list, with val appended. */
public static <T> List<T> modifyMyList(List<T> list, T val) {
List<T> xs = new ArrayList<T>(list);
xs.add(val);
return xs;
}
Aside: I wouldn't, as suggested by Saket return an immutable list. His argument for immutability and parallelism is valid. But most of the time Java programmers expect to be able to modify a collection, except in special circumstances. By making you method return an immutable collection, you limit it's reusability to such circumstances. (The caller can always make the list immutable if they want to: they know the returned value is a copy and won't be touched by anything else.) Put another way: Java is not Clojure. Also, if parallelism is a concern, look at Java 8 and streams (the new kind - not I/O streams).
Here's a different example:
/** Returns a copy of a list sans-nulls. */
public static <T> List<T> compact(Iterable<T> it) {
List<T> xs = new ArrayList<T>();
for(T x : it)
if(x!=null) xs.add(x);
return xs;
}
Note that I've genercized the method and made it more widely applicable to taking an Iterable instead of a list. In real code, I'd have two overloaded versions, one taking an Iterable and one an Iterator. (The first would be implemented by calling the second, with the iterable's iterator.) Also, I've made it static as there was no reason for your method to be an instance method (it does not depend on state from the instance).
Sometimes, though, if I'm writing library code, and if it is not clear whether a mutating or non-mutating implementation is more generally useful, I create both. Here's a fuller example:
/** Returns a copy of the elements from an Iterable, as a List, sans-nulls. */
public static <T> List<T> compact(Iterable<T> it) {
return compact(it.iterator());
}
public static <T> List<T> compact(Iterator<T> iter) {
List<T> xs = new ArrayList<T>();
while(iter.hasNext()) {
T x = iter.next();
if(x!=null) xs.add(x);
}
return xs;
}
/** In-place, mutating version of compact(). */
public static <T> void compactIn(Iterable<T> it) {
// Note: for a 'fluent' version of this API, have this return 'it'.
compactIn(it.iterator());
}
public static <T> void compactIn(Iterator<T> iter) {
while(iter.hasNext()) {
T x = iter.next();
if(x==null) iter.remove();
}
}
If this was in a real API I'd check the arguments for null and throw IllegalArgumentException. (NOT NullPointerException - though it is often used for this purpose. NullPointerException happens for other reasons as well, e.g. buggy code. IllegalArgumentException is better for invalid parameters.)
(There'd also be more Javadoc than actual code too!)
The first and second solution are very similar, The advantage of the second is to permit chaining. The question of "is it a good practise" is subjected to debate as we can see here:
Method Chaining in Java
So the real question is between the first solution with mutable list and the third with a unmutable list, and again, there is not a unique response, it is the same debate between returning String, which are immutable and using Stringbuffer, which are mutable but permits better performance.
If you need reliablility of your API , and if you don't have performance issues use immutable (the third solution). Use it if your lists are always small.
If you need only performance use a mutable list (the first solution)
I will recommend creating a new list in the method and returning an immutable list. That way your code will work even when you are passed in an Immutable list. It is generally a good practice to create immutable objects as we generally move towards functional programming and try to scale across multiple processor architectures.
List myList = modifyMyList(myList);
public List modifyMyList(List someList){
List returnList = new ArrayList();
returnList.addAll(someList);
returnList.add(someObject);
return Collections.unmodifiableList(returnList);
}
As I said in my other answer, I don't think you should mutate the list parameter. But there are times where you also don't want to take a copy of the original list and mutate the copy.
The original list might be large so the copy is expensive
You want the copy to be kept up-to-date with any updates to the original list.
In these scenarios, you could create a MergedList which is a view over two (or perhaps more) lists
import java.util.*;
public class MergedList<T> extends AbstractList<T> {
private final List<T> list1;
private final List<T> list2;
public MergedList(List<T> list1, List<T> list2) {
this.list1 = list1;
this.list2 = list2;
}
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
Iterator<T> it1 = list1.iterator();
Iterator<T> it2 = list1.iterator();
#Override
public boolean hasNext() {
return it1.hasNext() || it2.hasNext();
}
#Override
public T next() {
return it1.hasNext() ? it1.next() : it2.next();
}
};
}
#Override
public T get(int index) {
int size1 = list1.size();
return index < size1 ? list1.get(index) : list2.get(index - size1);
}
#Override
public int size() {
return list1.size() + list2.size();
}
}
The you could do
public List<String> modifyMyList(List<String> someList){
return new MergedList(someList, List.of("foo", "bar", "baz"));
}
Both ways will work because in this case java works with the reference of the List but i prefer the secound way because this solution works for pass by value too, not only for pass by reference.
Functionally both are same.
However when you expose your method as an API, second method may give an impression that it returns a new modified list other than the original passed list.
While the first method would make it clear (of-course based on method naming convention) that it will modify the original list (Same object).
Also, the second method returns a list, so ideally the caller should check for a null return value even if the passed list is non null (The method can potentially return a null instead of modified list).
Considering this I generally prefer to use method one over second.

How do I perform an action on each element of a List and return the result (without affecting the original of course)?

How do I write a static method in Java that will take a List, perform an action on each element, and return the result (without affecting the original of course)?
For example, if I want to add 2 to each element what goes in the ... here? The concrete return type must be the same, e.g. if my List is a LinkedList with values 1,2,3 I should get back a LinkedList with values 3,4,5. Similarly for ArrayList, Vector, Stack etc, which are all Lists.
I can see how to do this using multiple if (lst instanceof LinkedList) ... etc... any better way?
import java.util.List;
public class ListAdd {
static List<Integer> add2 (List<Integer> lst) {
...
return result;
}
}
There are already many answers, but I'd like to show you a different way to think of this problem.
The operation you want to perform is known as map in the world of functional programming. It is something we do really all the time in functional languages.
Let M<A> be some kind of container (in your case, M would be List, and A would be Integer; however, the container can be lots of other things). Suppose you have a function that transforms As into Bs, that is, f: A -> B. Let's write this function as of type F<A, B>, to use a notation closer to Java. Note that you can have A = B, as in the example you give (in which A = B = Integer).
Then, the operation map is defined as follows:
M<B> map(M<A>, F<A, B>)
That is, the operation will return a M<B>, presumably by applying F<A, B> to each A in M<A>.
In practice...
There's a brilliant library developed by Google, called Guava, which brings lot's of functional idioms to Java.
In Guava, the map operation is called transform, and it can operate on any Iterable. It has also more specific implementations that work directly on lists, sets, etc.
Using Guava, the code you want to write would look like this:
static List<Integer> add2(List<Integer> ns) {
return Lists.transform(ns, new Function<Integer, Integer>() {
#Override Integer apply(Integer n) { return n + 2; }
}
}
Simple as that.
This code won't touch the original list, it will simply provide a new list that calculates its values as needed (that is, the values of the newly created list won't be calculated unless needed -- it's called a lazy operation).
As a final consideration, it is not possible for you to be absolutely sure that you will be able to return exactly the same implementation of List. And as many others pointed out, unless there's a very specific reason for this, you shouldn't really care. That's why List is an interface, you don't care about the implementation.
Fundamentally, the List interface doesn't make any guarantees that you'll have a way to duplicate it.
You may have some luck with various techniques:
Using clone() on the passed in List, although it may throw, or (since it is protected in Object) simply not be accessible
Use reflection to look for a public no-argument constructor on the passed-in List
Try to serialize and deserialize it in order to perform a "deep clone"
Create some sort of factory and build in knowledge of how to duplicate each different kind of List your code may encounter (What if it's a wrapper created by unmodifiableList(), or some oddball custom implementation backed by a RandomAccessFile?)
If all else fails, either throw, or return an ArrayList or a Vector for lack of better options
You could use reflection to look for a public zero-arg constructor on the result of lst.getClass() and then invoke() it to obtain the List into which you'll place your results. The Java Collections Framework recommends that any derivative of Collection offer a zero-arg constructor. That way, your results we be of the same runtime class as the argument.
Here is a variant which does neither copies nor modifies the original list. Instead, it wraps the original list by another object.
public List<Integer> add2(final List<Integer> lst) {
return new AbstractList<Integer>() {
public int size() {
return lst.size();
}
public Integer get(int index) {
return 2 + lst.get(index);
}
};
}
The returned list is not modifiable, but will change whenever the original list changes.
(This implements the iterator based on index access, thus it will be slow for a linked list. Then better implement it based on AbstractSequentialList.)
Of course, the resulting list will obviously not be of the same class as the original list.
Use this solution only if you really only need a read-only two added view of your original list, not if you want a modified copy with similar properties.
The whole point of using an interface, in this case List, is to abstract the fact that the implementation is hidden behind the interface.
Your intention is clear to me, however: the Clonable interface supports creating a new instance with the same state. This interface might not be defined on your List.
Often it's a good idea to rethink this situation: why do you need to clone the List in this place, this class? Shouldn't your list-creator be responsible for cloning the list? Or shouldn't the caller, who knows the type, make sure he passes in a clone of his list?
Probably, if you look for the semantics as you defined it, you can implement all your supported Lists:
static Vector<Integer> addTwo(Vector<Integer> vector) {
Vector<Integer> copy = null; // TODO: copy the vector
return addTwo_mutable(copy);
}
static ArrayList<Integer> addTwo(ArrayList<Integer> aList) {
ArrayList<Integer> copy = null; // TODO: copy the array list
return addTwo_mutable(copy);
}
static LinkedList<Integer> addTwo(LinkedList<Integer> lList) {
LinkedList<Integer> copy = null; // TODO: copy the linked list
return addTwo_mutable(copy);
}
private <T extends List<Integer>> static T addTwo_mutable(T list) {
return list; // TODO: implement
}
Even, when you don't support a data-type, you'll get a nice compiler error that the specified method does not exists.
(code not tested)
Just to show you that what you want to do is not possible in the general case, consider the following class:
final class MyList extends ArrayList<Integer> {
private MyList() {
super.add(1);
super.add(2);
super.add(3);
}
private static class SingletonHolder {
private static final MyList instance = new MyList();
}
public static MyList getInstance() {
return SingletonHolder.instance;
}
}
It is a singleton (also, a lazy, thread-safe singleton by the way), it's only instance can be obtained from MyList.getInstance(). You cannot use reflection reliably (because the constructor is private; for you to use reflection, you'd have to rely on proprietary, non-standard, non-portable APIs, or on code that could break due to a SecurityManager). So, there's no way for you to return a new instance of this list, with different values.
It's final as well, so that you cannot return a child of it.
Also, it would be possible to override every method of ArrayList that would modify the list, so that it would be really an immutable singleton.
Now, why would you want to return the exact same implementation of List?
OK well someone mentioned reflection. It seems to be an elegant solution:
import java.util.*;
public class ListAdd {
static List<Integer> add2 (List<Integer> lst) throws Exception {
List<Integer> result = lst.getClass().newInstance();
for (Integer i : lst) result.add(i + 2);
return result;
}
}
Concise, but it thows an checked exception, which is not nice.
Also, wouldn't it be nicer if we could use the method on concrete types as well, e.g. if a is an ArrayList with values 1, 2, 3, we could call add2(a) and get an ArrayList back? So in an improved version, we could make the signature generic:
static <T extends List<Integer>> T add2 (T lst) {
T res;
try {
res = (T) lst.getClass().newInstance();
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
for (Integer i : lst) res.add(i + 2);
return res;
}
I think throwing a runtime exception is the least worst option if a list without a nullary construcor is passed in. I don't see a way to ensure that it does. (Java 8 type annotations to the rescue maybe?) Returning null would be kind of useless.
The downside of using this signature is that we can't return an ArrayList etc as the default, as we could have done as an alternative to throwing an exception, since the return type is guaranteed to be the same type as that passed in. However, if the user actually wants an ArrayList (or some other default type) back, he can make an ArrayList copy and use the method on that.
If anyone with API design experience reads this, I would be interested to know your thoughts on which is the preferable option: 1) returning a List that needs to be explicity cast back into the original type, but enabling a return of a different concrete type, or 2) ensuring the return type is the same (using generics), but risking exceptions if (for example) a singleton object without a nullary constructor is passed in?

A collection that represents a concatenation of two collections in Java

Is there a class that represents the concatenation of a collection with another collection? This class should be a Collection in itself, and should delegate all methods to the underlying (inner) collections - no extra memory should be allocated, nor any of the original collections modified.
Example usage:
Collection<String> foo = ...
Collection<String> bar = ...
// this should be O(1) memory and time
Collection<String> combined = concat(foo, bar);
if (combined.contains("Zee"))
...
for (String str : combined)
System.out.println(str);
As always for any collections stuff, look at google-collections. If you have Sets, specifically (not just a general collection), you want:
Set<String> combined = Sets.union(foo, bar);
which creates an unmodifiable view of the two sets. That is, changes in foo or bar will be reflected in combined (but combined.add() etc is not supported).
For the more generic case, you have Iterables.concat() but that merely lets you iterate over the joined item, the Iterable interface obviously doesn't include contains so you're a little hosed there.
The other collections utilities classes in google-collections (com.google.common.collect.Lists and com.google.common.collect.Collections2) don't contain any concatenation methods. Don't see why they couldn't, but at the moment they don't.
Your question is very vague. Especially "with another item another collection" is quite unclear.
You can at least add the contents of another Collection to the current Collection using Collection#addAll(). Here Collection can be anything of its subinterfaces/implementations, e.g. List or Set.
Example:
List<String> foos = Arrays.asList("foo1", "foo2", "foo3");
List<String> bars = Arrays.asList("bar1", "bar2", "bar3");
foos.addAll(bars); // Now foos contains everything.
Edit: Or do you actually want to create a new Collection based on an existing Collection and then add a new item to it? In this case just construct a new Collection with the existing Collection as constructor argument. E.g.:
List<String> foos = Arrays.asList("foo1", "foo2", "foo3");
List<String> bars = new ArrayList<String>(foos);
bars.add("bar"); // Now bars contains everything.
There is not, but writing it yourself should be straight forward
package ch.akuhn.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Concat {
public static <T> Iterable<T> all(final Iterable<T>... iterables) {
return new Iterable<T>() {
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
Iterator<Iterable<T>> more = Arrays.asList(iterables).iterator();
Iterator<T> current = more.hasNext() ? more.next().iterator() : null;
#Override
public boolean hasNext() {
if (current == null) return false;
if (current.hasNext()) return true;
current = more.hasNext() ? more.next().iterator() : null;
return this.hasNext();
}
#Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
return current.next();
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
}
And then
for (Object each: Concat.all(collection,whatever,etcetera,...)) {
// ...
}
Just wrote this code here, compile at your own risk!
PS, if you gonna write unit tests for this class, send 'em to me.
I think what you're asking for is a Java construct that allows you to put collections together without modifying the original collections. In other words, you have collections A and B, both of size N and M respectively. After the concat call, you still have collections A and B and their sizes are still N and M, however you have collection C as well which points to A and B, making its size N+M.
The answer is no, Java doesn't have anything out of the box that does this... However you could write a quick wrapper that wraps a series of collections and add those collections to it. (All it would do is maintain references to each of the collections) and you could expose get/insert methods as needed.
Apache Commons Collections also has a more general CompositeCollection class which can be used as an interface to an arbitrary number of Collections.
I'm not sure what your asking. My interpretation of your question is that your looking for the add method on the Collection. I don't think that's what you're asking though.
Try InterleavingEnumeration or apache's commons collections' ListUtils (ListUtils.union())

Categories