Set Collection for mutable objects in Java - java

In Java, a set only checks for equality of an object with objects already in the set only at insertion time. That means that if after an object is already present in the set, it becomes equal to another object in the set, the set will keep both equal objects without complaining.
EDIT: For example, consider a simple object, and assume that hashCode and equals are defined following best practices/
class Foo {
int foo;
Foo(int a){ foo = a; }
//+ equals and hashcode based on "foo"
}
Foo foo1 = new Foo(1);
Foo foo2 = new Foo(2);
Set<Foo> set = new HashSet<Foo>();
set.add(foo1);
set.add(foo2);
//Here the set has two unequal elements.
foo2.foo = 1;
//At this point, foo2 is equal to foo1, but is still in the set
//together with foo1.
How could a set class could be designed for mutable objects? The behavior I would expected would be the following: If at any time one of the objects in the set becomes equal to another object in the set, that object is deleted from the set by the set. Is there one already? Is there a programming language that would make this easier to accomplish?

I don't think this can be reliably done in Java in the general sense. There is no general mechanism for ensuring a certain action on mutation of an object.
There a few approaches for solutions that may be sufficient for your use case.
1. Observe elements for changes
You need to have control over the implementation of the types that go into the set
Small performance cost whenever an object in your set updates
You could try to enforce an observer like construction where your Set class is registered as an Observer to all its items. This implies you'd need to control the types of objects that can be put into the Set (only Observable objects). Furthermore, you'd need to ensure that the Observables notify the observer for every change that can affect hashcode and equals. I don't know of any class like this that exists already. Like Ray mentions below, you'll need to watch out for potential concurrency problems as well.
Example:
package collectiontests.observer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
public class ChangeDetectingSet<E extends Observable> implements Set<E>, Observer {
private HashSet<E> innerSet;
public void update(Observable o, Object arg) {
innerSet.remove(o);
innerSet.add((E)o);
}
public int size() {
return innerSet.size();
}
public boolean isEmpty() {
return innerSet.isEmpty();
}
public boolean contains(Object o) {
return innerSet.contains(o);
}
public Iterator<E> iterator() {
return innerSet.iterator();
}
public Object[] toArray() {
return innerSet.toArray();
}
public <T> T[] toArray(T[] a) {
return innerSet.toArray(a);
}
public boolean add(E e) {
e.addObserver(this);
return innerSet.add(e);
}
public boolean remove(Object o) {
if(o instanceof Observable){
((Observable) o).deleteObserver(this);
}
return innerSet.remove(o);
}
public boolean containsAll(Collection<?> c) {
return innerSet.containsAll(c);
}
public boolean addAll(Collection<? extends E> c) {
boolean result = false;
for(E el: c){
result = result || add(el);
}
return result;
}
public boolean retainAll(Collection<?> c) {
Iterator<E> it = innerSet.iterator();
E el;
Collection<E> elementsToRemove = new ArrayList<E>();
while(it.hasNext()){
el = it.next();
if(!c.contains(el)){
elementsToRemove.add(el); //No changing the set while the iterator is going. Iterator.remove may not do what we want.
}
}
for(E e: elementsToRemove){
remove(e);
}
return !elementsToRemove.isEmpty(); //If it's empty there is no change and we should return false
}
public boolean removeAll(Collection<?> c) {
boolean result = false;
for(Object e: c){
result = result || remove(e);
}
return result;
}
public void clear() {
Iterator<E> it = innerSet.iterator();
E el;
while(it.hasNext()){
el = it.next();
el.deleteObserver(this);
}
innerSet.clear();
}
}
This incurs a performance hit every time the mutable objects change.
2. Check for changes when Set is used
Works with any existing object you want to put into your set
Need to scan the entire set every time you require info about the set (performance cost may get significant if your set gets very large).
If the objects in your set change often, but the set itself is used rarely, you could try Joe's solution below. He suggests to check whether the Set is still correct whenever you call a method on it. As a bonus, his method will work on any set of objects (no having to limit it to observables). Performance-wise his method would be problematic for large sets or often used sets (as the entire set needs to be checked at every method call).
Possible implementation of Joe's method:
package collectiontests.check;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class ListBasedSet<E> {
private List<E> innerList;
public ListBasedSet(){
this(null);
}
public ListBasedSet(Collection<E> elements){
if (elements != null){
innerList = new ArrayList<E>(elements);
} else {
innerList = new ArrayList<E>();
}
}
public void add(E e){
innerList.add(e);
}
public int size(){
return toSet().size();
}
public Iterator<E> iterator(){
return toSet().iterator();
}
public void remove(E e){
while(innerList.remove(e)); //Keep removing until they are all gone (so set behavior is kept)
}
public boolean contains(E e){
//I think you could just do innerList.contains here as it shouldn't care about duplicates
return innerList.contains(e);
}
private Set<E> toSet(){
return new HashSet<E>(innerList);
}
}
And another implementation of the check always method (this one based on an existing set). This is the way to go if you want to reuse the existing sets as much as possible.
package collectiontests.check;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.TreeSet;
public class ChangeDetectingSet<E> extends TreeSet<E> {
private boolean compacting = false;
#SuppressWarnings("unchecked")
private void compact(){
//To avoid infinite loops, make sure we are not already compacting (compact also gets called in the methods used here)
if(!compacting){ //Warning: this is not thread-safe
compacting = true;
Object[] elements = toArray();
clear();
for(Object element: elements){
add((E)element); //Yes unsafe cast, but we're rather sure
}
compacting = false;
}
}
#Override
public boolean add(E e) {
compact();
return super.add(e);
}
#Override
public Iterator<E> iterator() {
compact();
return super.iterator();
}
#Override
public Iterator<E> descendingIterator() {
compact();
return super.descendingIterator();
}
#Override
public NavigableSet<E> descendingSet() {
compact();
return super.descendingSet();
}
#Override
public int size() {
compact();
return super.size();
}
#Override
public boolean isEmpty() {
compact();
return super.isEmpty();
}
#Override
public boolean contains(Object o) {
compact();
return super.contains(o);
}
#Override
public boolean remove(Object o) {
compact();
return super.remove(o);
}
#Override
public void clear() {
compact();
super.clear();
}
#Override
public boolean addAll(Collection<? extends E> c) {
compact();
return super.addAll(c);
}
#Override
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
compact();
return super.subSet(fromElement, fromInclusive, toElement, toInclusive);
}
#Override
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
compact();
return super.headSet(toElement, inclusive);
}
#Override
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
compact();
return super.tailSet(fromElement, inclusive);
}
#Override
public SortedSet<E> subSet(E fromElement, E toElement) {
compact();
return super.subSet(fromElement, toElement);
}
#Override
public SortedSet<E> headSet(E toElement) {
compact();
return super.headSet(toElement);
}
#Override
public SortedSet<E> tailSet(E fromElement) {
compact();
return super.tailSet(fromElement);
}
#Override
public Comparator<? super E> comparator() {
compact();
return super.comparator();
}
#Override
public E first() {
compact();
return super.first();
}
#Override
public E last() {
compact();
return super.last();
}
#Override
public E lower(E e) {
compact();
return super.lower(e);
}
#Override
public E floor(E e) {
compact();
return super.floor(e);
}
#Override
public E ceiling(E e) {
compact();
return super.ceiling(e);
}
#Override
public E higher(E e) {
compact();
return super.higher(e);
}
#Override
public E pollFirst() {
compact();
return super.pollFirst();
}
#Override
public E pollLast() {
compact();
return super.pollLast();
}
#Override
public boolean removeAll(Collection<?> c) {
compact();
return super.removeAll(c);
}
#Override
public Object[] toArray() {
compact();
return super.toArray();
}
#Override
public <T> T[] toArray(T[] a) {
compact();
return super.toArray(a);
}
#Override
public boolean containsAll(Collection<?> c) {
compact();
return super.containsAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
compact();
return super.retainAll(c);
}
#Override
public String toString() {
compact();
return super.toString();
}
}
3. Use Scala sets
You could cheat and do away with mutable objects (in the sense that instead of mutating, you'd create a new one with one property changed) in your set. You can look at the set in Scala (I thought it was possible to call Scala from Java, but I'm not 100% sure): http://www.scala-lang.org/api/current/scala/collection/immutable/IndexedSeq.html

You will not find a general datastructure that can take just any object for this purpose. That kind of set would have to constantly monitor its elements, which among other things would lead to a lot of questions on concurrency.
However, I can imagine something based on the practically unknown class java.util.Observable. You could e.g. write a class ChangeAwareSet implements Set<? extends Observable>, Observer. When an element is added to this Set, it would register as an Observer and so be notified on all changes to that object. (But don't expect this to be very efficient, and you might encounter concurrency problems in this scenario as well.)

You can get the behaviour you're after by using another collection, such as an ArrayList. The contains and remove methods for a List make no assumptions about objects remaining unchanged.
Since changes can happen at any time, there isn't much room for optimisation. Any operations would need to perform a full scan over all contents, as any object could have changed since the last operation.
You may or may not wish to override add to check whether the object currently appears to be present. Then, when using or printing, use new HashSet(list) to eliminate objects which are currently duplicate.

Your problem is the identity of an object vs state. identity is not mutable over time, state is. In your set, you should preferably rely on identity because this is the only warranty for not introducing duplication by mutation, or you must rebuild the Set each time there is an element mutation. Technically, equals() and hashCode() should be constant over time to reflect identity.
As #assylias commented, there is certainly an alternative if you need to have a collection with combined identity and state.
have a Map<TheObject, List<State>> rather than a Set<TheObjectWithState>
remove the object from the Set before mutation, then check if it exists after mutation, add it if there is no duplicate.

You have two broad strategies here, I expect both wont give great performance (but that might not be a problem for your use).
Have your set register with the objects for changes.
Instead of modifying the set constantly, only update it when it is used.
Note that these solutions will have a slight difference in behavior.
Register for changes
This involves adding an Observable pattern (or alternatively a listener) to all objects stored in the set.
When an object is in the Set, the Set will register for changes. When an object changes it will signal the Set it has changed and the Set will change accordingly.
The most naive implementation is to just remove all equals objects and then re-add the object at any change. The naive implementation is always a good start so you can write a proper test set, and from there on you can improve the performance step by step.
Thread safety
Be careful when using this Set or the objects in it from multiple threads. Which a solution like this there are a lot of risks for deadlocks, so you would probably end up with a single ReadWriteLock for both the Set and the objects stored in it.
Update it when it is used
An alternative is a lazy strategy: only update the set when it is used. This is very useful when there are many changes to the objects but the set is not used as often.
It uses the following set idea (this makes me think of Schrodinger's cat):
If nobody is looking at the Set, does it matter what is in it?
An object is only defined by it's behavior on it's interface(s). So instead you can evaluate your set (and update it accordingly) at the point when the information is used.
General remarks
Here follow some remarks that apply to both choices.
Desired behavior
Watch out that you might run in to really weird behavior with a set like this. When you remove an object from the Set because it has become equal to another object, the outside world will not know you have removed that object.
See for instance the following, suing your Foo class:
Foo foo1 = new Foo(1);
Foo foo2 = new Foo(2);
Set<Foo> set = new MySet<Foo>();
set.add(foo1);
set.add(foo2);
foo2.foo = 1; // foo or foo2 is removed from the set.
foo2.foo = 3; // now the set contains with a foo or with 1 or with 3.
As an alternative you could take the objects stored in a list and convert them to set at the time you use.

I am still not sure you understand the implications. If you have 2 objects which CAN equal each other at any point in time, may not equal each other at another point in time, therefore by default they are deemed as separate objects even though at the moment they may appear to be identical.
I would go about it at a different angle, and check if the set contains what the object will become when you perform the change, if you do not want it to exist in that set when it does equal another object.

Use safe publishing: Don't allow access to the Set or its elements; publish a deep copy instead.
You need a way of making a copy of a Foo; I'll assume a copy constructor.
private Set<Foo> set;
public Set<Foo> getFoos() {
// using java 8
return set.stream().map(Foo::new).collect(Collectors.toSet());
}
You should also save a copy of a Foo, rather than saving a foo, because the caller will have a reference to the added Foos, so the client can mutate them. Add an accessor method for this:
public boolean addFoo(Foo foo) {
return set.add(new Foo(foo));
}

This is a great question! Perhaps it is the source of many bugs! This is not just an issue with duplicates. Almost all the methods will return incorrect answers even without duplicates. Consider a hash set. If the hash changes even without creating a duplicate, the contains method will now return incorrect results since the object is in the wrong hash bucket. Similarly remove will not work correctly. For sorted sets, the iterator order will be incorrect.
I like the Observable pattern mentioned by #Thirler. Other solutions seem inefficient. In the observable approach mentioned there, there is a dependency that that implementer of the elements to be added to the set correctly notifies the set whenever and update occurs. The approach I mention here is somewhat more restrictive, but passes responsibility for the correct implementation to the set creator. So as long as the set is implemented correctly it will work for all users of the set. (See below for more on why the observer pattern is hard to implemented)
Here is the basic idea: Suppose that you want to create a set of foo object. We'll create a class called SetFoo. All aspects of foo objects are maintained by the set itself, including construction, and any changes to it. There is no way for any other user to create a Foo object directly because it is an inner class of SetFoo and the constructor is either private or protected. For example lets suppose we implement a class SetFoo where Foo has methods void setX(int x) and Foo int getX(). The class SetFoo would have methods like:
Foo instance(int x) //Returns the instance of foo if it exists, otherwise creates a new one and returns it.
Let's say that internally SetFoo maintains a hashset of Foo objects.
Now the setX method of Foo would be defined to remove and re-add the element to the hashset if the value of x changes.
We can extend the idea of SetFoo to contain any number of elements, all of which are maintained by the set. This is really easy to implement for any kind of objects, however, it does require that the elements are all maintained by the set (including construction and all setter methods). Of course to make it multi-thread safe would take more work.
From the point of view of any user of the SetFoo class things would be simple:
Foo f = setFoo.instance(1);
....
f.setX(2);
...
f.setX(3)
f = setFoo.instance(1); // Would internally create a new one since it was changed.
f= setFoo.instance(3) // Already in the set so no new one is created.
Now we can also add other methods to SetFoo, like
boolean contains (int x);
Iterator<Integer> iterator();
boolean remove(int x);
etc...
or we can add various methods to Foo:
remove() // removes foo from the set.
exists() // if foo still in the set?
add() // add foo back to the set
In the case where the elements can contain many fields we can have a FooSpec class. Suppose Foo contains an int x and int y. Then FooSpec would have getX, SetX, getY, setY methods and could be constructed using new FooSpec. Now setFoo would have methods like:
Foo instance(FooSpec fooSpec)
Collection<Foo> instanceAll(Collection<FooSpec> col)
...etc
So now you might be wondering why the observer pattern approach is subject to potential errors. With that approach the user of the set must correctly notify the set when it changes. That is effectively the same level of difficulty as as implementing a deeply immutable object (which may not be that easy). For example if the elements of the set are themselves collections or collections of collections, then you would need to make sure that you notify the set whenever anything in the collection (deeply) changes.
Leaving the responsibility to "deeply" notify the set, to the user of the set, would place a lot of burden on the developer. Better to implement a framework that would provide for objects that "deeply" notify.

Set does makes use of hashCode and equals method. But when you say
it becomes equal to another object in the set, the set will keep both equal objects without complaining.
It's not the case. If you run add method by adding already existing element, it will return you false saying hey you already have an object in set.
Set is a mathematical term which does not allow duplicates and is the case with Java Set. Set is agnostic about whether the object that you are inserting into it is mutable or immutable. It's just like a collection which hold values.
Edit:
As per the code, checks in set would be done when you insert the element to the Set and then if it changes, it wont care about it.

Here are a few aspects for one approach I see
Use a 'Dynamic Element Set'
It might be good to have a clear distinction between having a mutable set class for immutable elements, as well as another set class for mutable elements
The set class for mutable elements would be 'dynamic element sets', and require each element to have a pointer to the containing set
Element itself registers change on modification
You could have to have a corresponding wrapper class for the elements contained in the set, so that it can register with the containing element
Hash table for fast single-threaded uniqueness checks
When adding an element to the set, the set will compute a hash of the element, and add that to a table (I'm sure thats how sets work anyhow)
Use this to check uniqueness and do elimination in O(1) time
Dirty / clean state for multithreaded cases
When you update an element, mark the containing set as 'dirty'
When the containing set is dirty, you can at some point rerun the uniqueness test to see if all elements are unique.
While that is happening, it probably should block any modifications to the elements until it has completed
With this, you probably deviate from exact uniqueness property.
Consider this: You have 3 elements in the list: A, B, and C, each with unique values
You change element B to same value as A
Mark as dirty
Change element A to a different, unique value
Still marked as dirty
Run the uniqueness check
So if you don't need absolute set property, but only an approximate, this might work
Otherwise if you need absolute set property, in a multithreaded case might not work
Updates seem to be pretty cheap, so you might be able to get away with it
Is this really a 'set'?
So, this kinda assumes that the elements are only modified from the provided interface for the set
When you wrap the base class of the element into the set, it should probably make a deep copy of the element to help prevent an element getting modifications from a non-registering reference object
So its not just a 'set', but rather imposes a requirement on the type of element being passed
It adds an interface layer to the element class
As such, the elements themselves are part of a new object in a sense I guess
Other thoughts
So of course, if one time an element can become the same as another element, then in the future it could also change to being different again
You are implying that a solution being searched for would be needed in a specific problem where that kind property is needed: Elements that are transiently duplicate need to be eliminated

Related

How to change the object of the class itself from inside itself?

How to change the object of the class itself from inside itself? I have one class like this:
public class AdvancedArrayList<T> extends ArrayList<T>
And I want to assign a new object to itself. But, I am unable to do that. Just see this code:
AdvancedArrayList<T> abcd = this; // works fine
this = abcd; // ERROR: variable expected
And this is my entire class:
public class AdvancedArrayList<T> extends ArrayList<T> {
public void reverse(){
Collections.reverse(this);
}
public void removeDuplicates(){
ArrayList<T> wordDuplicate = new ArrayList<>();
ArrayList<T> tempList= new ArrayList<>();
for (T dupObject : wordDuplicate) {
if (!tempList.contains(dupObject)) {
tempList.add(dupObject);
}
}
this = tempList;
}
}
So, how can I change the object of the class itself?
Your #removeDuplicates method is attempting to mutate the list object it belongs to (known by this, within this class), and as such should actually make those modifications to the list itself (rather than a copy). Note as well, that by iterating your newly-made list wordDuplicate, the for loop will not actually execute (since there are no values inside the list). I would personally keep track using a Set (namely, HashSet with a roughly O(1) lookup, aka nearly constant-time), while taking advantage of the Iterator#remove method:
public void removeDuplicates() {
Set<T> seen = new HashSet<>();
Iterator<T> itr = this.iterator(); //similar to the mechanics behind for-each
while (itr.hasNext()) { //while another element can be found
T next = itr.next(); //get the next element
if (!seen.add(next)) { //#add returns "true" only if it was not in the Set previously
itr.remove(); //if it was previously in the set, remove it from the List
}
}
}
Note as well, that the semantics you are describing nicely fit the definition of a Set, which is a collection of items that do not contain duplicates. There are varients of Set (i.e. LinkedHashSet) which also allow linear traversal of the elements, based on insertion-order.
For a simpler, non-iterator solution, you could also do a "dirty swap" of the elements after your calculation, which would be similar to what you attempted to achieve via this = list:
public void removeDuplicates() {
Set<T> seen = new LinkedHashSet<>(); //to preserve iteration order
for (T obj : this) { //for each object in our current list
seen.add(obj); //will only add non-duplicates!
}
this.clear(); //wipe out our old list
this.addAll(seen); //add back our non-duplicated elements
}
This can be quicker to write, but would be less performant than the in-place removal (since the entire list must be wiped and added to again). Lastly, if this is a homework problem, try to avoid copy-pasting code directly, and instead write it out yourself at the very least. Merely working towards a solution can help to solidify the information down the line.
It's not possible in Java. this cannot be reassigned. Why (and when) do you need to re-assign an object from within itself?
When you have code such as obj.replace(otherObj) with an imaginary implementation of void replace(Object other) { this = other; }, then why not simply write obj = otherObj to update the reference?
Further clarifications after comments:
ArrayList is not meant to be inherited. If you want to write your own list collection, extend AbstractList. Your custom list can then use composition to delegate to its inner list.

Need to create a Binary Search Tree with a custom comparator, can't seem to get it to work

I'm trying to create a Binary Search Tree using a TreeSet. I'm aware that by definition, a set does not contain any duplicate entries. However, I am sure that if I create my own comparator, I can allow the TreeSet to take in duplicate entries. I've done so:
public class A3BSTree <E> implements Tree <E> {
private TreeSet<E> tree;
private LinkedList<E> arr1;
private MyComparator comp;
public A3BSTree(){
tree = new TreeSet<>(comp);
}
...
...
...
private class MyComparator implements Comparator<E> {
#SuppressWarnings("unchecked")
#Override
public int compare(E e1, E e2) {
if (((A3BSTree<E>.MyComparator) e1).compareTo(e2) < 0) {
return -1;
}
else if (e1.equals(e2)) {
return 0;
}
else {
return 1;
}
}
public int compareTo(E e) {
return this.compareTo(e);
}
}
}
I don't want the answer, I just need an explanation on why the TreeSet still won't take in duplicates. I just need to be steered in the right direction. Could the problem be that I cannot create a Comparator with generics?
java.util.TreeSet add() method
java.util.TreeSet class uses the add method to add elements into the Set. This method does not allow duplicates. It detects duplicates using the equals() method as mentioned in Javadoc.
public boolean add(E e)
Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.
Current comparator implementation
As per your Comparator implementation, you expect the equals method to identify duplicates (probably you have overridden it?).
} else if (e1.equals(e2)) {
return 0;
}
If that is the case, I believe the behavior of TreeSet is correct in rejecting the duplicates based on the equals() method.
On the other hand, may be it is better to use Comparable approach rather than Comparator here as that allows objects to be comparable with its own instances (difference is explained here).

Java List.contains(Object with field value equal to x)

I want to check whether a List contains an object that has a field with a certain value. Now, I could use a loop to go through and check, but I was curious if there was anything more code efficient.
Something like;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
I know the above code doesn't do anything, it's just to demonstrate roughly what I am trying to achieve.
Also, just to clarify, the reason I don't want to use a simple loop is because this code will currently go inside a loop that is inside a loop which is inside a loop. For readability I don't want to keep adding loops to these loops. So I wondered if there were any simple(ish) alternatives.
Streams
If you are using Java 8, perhaps you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
Or alternatively, you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
This method will return true if the List<MyObject> contains a MyObject with the name name. If you want to perform an operation on each of the MyObjects that getName().equals(name), then you could try something like this:
public void perform(final List<MyObject> list, final String name){
list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
Where o represents a MyObject instance.
Alternatively, as the comments suggest (Thanks MK10), you could use the Stream#anyMatch method:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().anyMatch(o -> name.equals(o.getName()));
}
You have two choices.
1. The first choice, which is preferable, is to override the `equals()` method in your Object class.
Let's say, for example, you have this Object class:
public class MyObject {
private String name;
private String location;
//getters and setters
}
Now let's say you only care about the MyObject's name, that it should be unique so if two `MyObject`s have the same name they should be considered equal. In that case, you would want to override the `equals()` method (and also the `hashcode()` method) so that it compares the names to determine equality.
Once you've done this, you can check to see if a Collection contains a MyObject with the name "foo" by like so:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
However, this might not be an option for you if:
You are using both the name and location to check for equality, but you only want to check if a Collection has any `MyObject`s with a certain location. In this case, you've already overridden `equals()`.
`MyObject` is part of an API that you don't have liberty to change.
If either of these are the case, you'll want option 2:
2. Write your own utility method:
public static boolean containsLocation(Collection<MyObject> c, String location) {
for(MyObject o : c) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Alternatively, you could extend ArrayList (or some other collection) and then add your own method to it:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Unfortunately there's not a better way around it.
This is how to do it using Java 8+ :
boolean isJohnAlive = list.stream().anyMatch(o -> "John".equals(o.getName());
Google Guava
If you're using Guava, you can take a functional approach and do the following
FluentIterable.from(list).find(new Predicate<MyObject>() {
public boolean apply(MyObject input) {
return "John".equals(input.getName());
}
}).Any();
which looks a little verbose. However the predicate is an object and you can provide different variants for different searches. Note how the library itself separates the iteration of the collection and the function you wish to apply. You don't have to override equals() for a particular behaviour.
As noted below, the java.util.Stream framework built into Java 8 and later provides something similar.
Collection.contains() is implemented by calling equals() on each object until one returns true.
So one way to implement this is to override equals() but of course, you can only have one equals.
Frameworks like Guava therefore use predicates for this. With Iterables.find(list, predicate), you can search for arbitrary fields by putting the test into the predicate.
Other languages built on top of the VM have this built in. In Groovy, for example, you simply write:
def result = list.find{ it.name == 'John' }
Java 8 made all our lives easier, too:
List<Foo> result = list.stream()
.filter(it -> "John".equals(it.getName())
.collect(Collectors.toList());
If you care about things like this, I suggest the book "Beyond Java". It contains many examples for the numerous shortcomings of Java and how other languages do better.
Binary Search
You can use Collections.binarySearch to search an element in your list (assuming the list is sorted):
Collections.binarySearch(list, new YourObject("a1", "b",
"c"), new Comparator<YourObject>() {
#Override
public int compare(YourObject o1, YourObject o2) {
return o1.getName().compareTo(o2.getName());
}
});
which will return a negative number if the object is not present in the collection or else it will return the index of the object. With this you can search for objects with different searching strategies.
Map
You could create a Hashmap<String, Object> using one of the values as a key, and then seeing if yourHashMap.keySet().contains(yourValue) returns true.
Eclipse Collections
If you're using Eclipse Collections, you can use the anySatisfy() method. Either adapt your List in a ListAdapter or change your List into a ListIterable if possible.
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
If you'll do operations like this frequently, it's better to extract a method which answers whether the type has the attribute.
public class MyObject
{
private final String name;
public MyObject(String name)
{
this.name = name;
}
public boolean named(String name)
{
return Objects.equals(this.name, name);
}
}
You can use the alternate form anySatisfyWith() together with a method reference.
boolean result = list.anySatisfyWith(MyObject::named, "John");
If you cannot change your List into a ListIterable, here's how you'd use ListAdapter.
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Note: I am a committer for Eclipse ollections.
Predicate
If you dont use Java 8, or library which gives you more functionality for dealing with collections, you could implement something which can be more reusable than your solution.
interface Predicate<T>{
boolean contains(T item);
}
static class CollectionUtil{
public static <T> T find(final Collection<T> collection,final Predicate<T> predicate){
for (T item : collection){
if (predicate.contains(item)){
return item;
}
}
return null;
}
// and many more methods to deal with collection
}
i'm using something like that, i have predicate interface, and i'm passing it implementation to my util class.
What is advantage of doing this in my way? you have one method which deals with searching in any type collection. and you dont have to create separate methods if you want to search by different field. alll what you need to do is provide different predicate which can be destroyed as soon as it no longer usefull/
if you want to use it, all what you need to do is call method and define tyour predicate
CollectionUtil.find(list, new Predicate<MyObject>{
public boolean contains(T item){
return "John".equals(item.getName());
}
});
Here is a solution using Guava
private boolean checkUserListContainName(List<User> userList, final String targetName){
return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
#Override
public boolean apply(#Nullable User input) {
return input.getName().equals(targetName);
}
});
}
contains method uses equals internally. So you need to override the equals method for your class as per your need.
Btw this does not look syntatically correct:
new Object().setName("John")
If you need to perform this List.contains(Object with field value equal to x) repeatedly, a simple and efficient workaround would be:
List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
fieldOfInterestValues.add(obj.getFieldOfInterest());
}
Then the List.contains(Object with field value equal to x) would be have the same result as fieldOfInterestValues.contains(x);
Despite JAVA 8 SDK there is a lot of collection tools libraries can help you to work with, for instance:
http://commons.apache.org/proper/commons-collections/
Predicate condition = new Predicate() {
boolean evaluate(Object obj) {
return ((Sample)obj).myField.equals("myVal");
}
};
List result = CollectionUtils.select( list, condition );

java prevent class from overriding equals

I want to use java.util.Set (and other collections) but with a twist: I want contains() , add(), etc. to call Object's equals() at all times (that is operate based on identity rather than equality more generally). I think I have a way, but it has big drawbacks. Is there a proper way to do this? Sorry if I'm missing something obvious.
Here's what I've done:
public class OnlySelfEqual {
public final boolean equals(Object o){
return super.equals(o);
}
}
public class Example{
private Set<T extends OnlySelfEqual> set;
//etc
}
The main problem I see with this (there may be numerous others) is that all Ts have to extend from a class rather than implement an interface, which is pretty restrictive. I think what I want would be something like a 'reverse' interface which lists methods that subtypes cannot implement (override). I'm pretty sure that doesn't exist though. Any suggestions?
java.util.IdentityHashMap is a Map implementation that deliberately violates the Map contract by using == rather than equals(), so you could get a Set with the same behaviour using e.g.
Set<String> set = Collections.newSetFromMap(new IdentityHashMap<String, Boolean>());
You could wrap your objects inside a container which will implement equals() using the wrapped objects' identity:
public class Wrapper<T> {
// Either public (it's final), or private with a getter
public final T element;
public Wrapper(T element) {
this.element = element;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o == null || o.getClass() != getClass()) {
return false;
}
return element == ((Wrapper<?>) o).element;
}
public int hashCode() {
return System.identityHashCode(element);
}
}
You then use Set<Wrapper<T>>, List<Wrapper<T>>, etc.
If you use Guava (which contains a lot of useful stuff complementing the JDK), you can directly use its Equivalence class (and Equivalence.Wrapper) to get that result, or other ones based on different strategies.
If I recall correctly, what you're looking for is:
T t = ...
((Object)t).equals( other );
I might be mistaken as to the syntax..

Java - Retrieving amount of types in list

I have a list. The list can contain multiple items of the same enum type.
Lets say i have an enum : TOY which has values: BALL, DOLL, PLAYSTATION. I want to know how many PLAYSTATION items are in a list with the type TOY. (ie, List<Toy> toys)
What is the best possible solution for this? I don't want to keep iterating through the list everytime.
You can use Apache commons-collections' HashBag. It has a getCount(Object) method which will suit you.
java.util.Collections has a method called frequency(Collection c, Object type).
Usage in my question:
int amountOfPlayStations = Collections.frequency(toys, TOY.PLAYSTATION);
Why don't you create a decorator for the type of list you're using which stores a list of counts for each enum type have been added/removed internally. That way you could use it as a normal list but also add some extra functionality for querying how many of which type are currently contained.
All you'd need to do would be to override the add/remove/addAll etc methods and increment your counters before passing it on to the real list type. The best part about it would be that you could decorate any list type with your new wrapper.
At the very least, a utility method like:
public int count(List<Toy> haystack, Toy needle) {
int result;
for (Toy t : haystack) {
if (t == needle) {
result++;
}
}
return result;
}
Would let you concisely refer to the number of PLAYSTATIONs from elsewhere in the code. Alternatively if you knew the list was unlikely to change, building a Map<Toy, Integer> would let you build up the counts for all items once.
If you don't want to have to iterate over the entire collection each time, another alternative would be to write a ForwardingList implementation. The main benefits of this over the HashBag suggestion are:
it supports generics
it implements the List interface, so you can pass it to any method that expects a List
There is a downside to this approach however, in that you have to write a bit of plumbing code to get it up and running.
Below is a quick example of how you could do it. Note that if you do this you should override all methods that add/delete from the list, otherwise you may end up in an inconsistent state:
import com.google.common.collect.ForwardingList;
public class CountingList<E> extends ForwardingList<E> {
private List<E> backingList = new LinkedList<E>();
private Map<E, Integer> countMap = new HashMap<E, Integer>();
#Override
protected List<E> delegate() {
return backingList;
}
#Override
public boolean add(E element) {
backingList.add(element);
if(countMap.containsKey(element)) {
countMap.put(element, countMap.get(element) + 1);
} else {
countMap.put(element, 1);
}
return true;
}
public int getCount(E element) {
Integer count = countMap.get(element);
return count != null ? count.intValue() : 0;
}
}
Extend java.util.List method and override all mutator methods, i.e. the ones that are used for add or delete elements and also ones used to clear the list. Add a reference to a private java.util.Map which will hold the number of items per type. Add accessor methods which will return current number of elements per type.
The HashBag (by Bozho) seems to be your best bet. But a bit more general would be Googles Collections 2 with an appropriate Predicate:
List<Toy> toys;
List<Toy> playstations = Collections2.filter( toys, new Predicate() {
boolean apply(TOY toy){
return toy == TOY.PLAYSTATION;
}
});
Besides all those solutions (I have a weakness for the Collections.Frequency call), i would recommend you to take a look at google collections, and particularly to [Collections2.transform][2], which could give you a live view on items.
[2]: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Collections2.html#transform(java.util.Collection, com.google.common.base.Function)

Categories

Resources