I want to use a HashSet to store some objects:
public class StoredObject{
Type type; //Type is an enum
//other fields
Type getType(){return type;}
}
Now, I want to store only one StoredObject of the same Type, so I override contains() in a subclass of HashSet:
public MySet<E extends StoredObject> extends java.util.HashSet<E>{
#Override
public boolean contains(Object o) {
if(StoredObject.class.isAssignableFrom(o.getClass())) {//if o implements StoredObject
for(StoredObject s : this) {
if(s.getType() == ((StoredObject) o).getType()) return true;
}
}
return false
}
}
Before this I wanted to use HashSet and modify the equals() of StoredObject. However, the way above seems like a shorter and safer way, especially as in my case the stored objects all implement an interface and don't extend the same class.
Now my question: Is this implementation safe? I tried to search for things it could break, but did not find any. I read that overriding equals() can break Collections.
Also, does this subclass defeats the purpose of an HashSet, since it does not use the HashMap for contains()?
HashMap<Type,StoredObject> is the appropriate collection for this.
If you override equals(Object) then you must also override hashCode (it's also not a bad idea to make it implement Comparable and perhaps override toString). Use the #Override annotation to ensure you have the right parameter types and spelling - very easy to get wrong and confusing to debug.
What can go wrong?
There's a lot of methods in HashSet to override, so that's a lot of work.
More methods may be added to HashSet in future versions of Java - how are you going to look out for this?
contains should be an O(1) operation (assuming a good distribution of hash codes), but the OP implementation is O(n).
Set.equals on another Set will report incorrect results.
Note also that StoredObject.class.isAssignableFrom(o.getClass()) is better written as o instanceof StoredObject (assuming you've got isAssignableFrom the right way around).
Is this implementation safe?
Absolutely not. There are other methods on HashSet that wouldn't work correctly, e.g. add(), leaving the size of the set incorrect.
Besides, that implementation would totally ruin the performance of the contains method, making it run in O(n) instead of O(1).
If you need a Set with a definition of equality that differs from the objects natural definition as implemented by equals() and hashCode(), use a TreeSet and supply a custom Comparator.
class MySet<E extends StoredObject> extends java.util.TreeSet<E> {
public MySet() {
super(Comparator.comparing(StoredObject::getType));
}
}
I do agree with Tom Hawtin - tackline, that HashMap<Type, StoredObject> is a better option, because it allows you to get the StoredObject for a given Type, which is otherwise very difficult to do with a Set. It also allows you to check for existence given just a Type, without having to create a dummy StoredObject object for the check.
Related
How to make two objects in Java comparable using "<" or ">"
e.g.
MyObject<String> obj1= new MyObject<String>(“blablabla”, 25);
MyObject<String> obj2= new MyObject<String>(“nannaanana”, 17);
if (obj1 > obj2)
do something.
I've made MyObject class header as
public class MyObject<T extends Comparable<T>> implements Comparable<MyObject<T>>
and created method Comp but all the gain I got is now I can use "sort" on the list of objects, but how can I compare two objects to each other directly? Is
if(obj1.compareTo(obj2) > 0)
do something
the only way?
You cannot do operator overloading in Java. This means you are not able to define custom behaviors for operators such as +, >, <, ==, etc. in your own classes.
As you already noted, implementing Comparable and using the compareTo() method is probably the way to go in this case.
Another option is to create a Comparator (see the docs), specially if it doesn't make sense for the class to implement Comparable or if you need to compare objects from the same class in different ways.
To improve the code readability you could use compareTo() together with custom methods that may look more natural. For example:
boolean isGreaterThan(MyObject<T> that) {
return this.compareTo(that) > 0;
}
boolean isLessThan(MyObject<T> that) {
return this.compareTo(that) < 0;
}
Then you could use them like this:
if (obj1.isGreaterThan(obj2)) {
// do something
}
Using Comparable.compareTo(T) is the only option (or Comparator). The interface only defines that one method (while Comparator adds equals), and it compares this object with the specified object for order. Further, Java does not permit operator overloading (so you won't be able to directly change the operand used for invoking that method; or in fact modify the interface).
It is not the only way. You can implement a Comparator as well. Comparator uses compare() method as oppose to Comparable which uses compareTo() method.
The reason you can't use > or < to compare objects directly is because Java won't know which variable you want to use for the comparison (as there might exist more than one variable in the object).
In order to compare objects, those objects must be comparable. You need to define and tell Java how you want to compare them.
Java collection provides a sort method. However some school does give assignment of asking you to write you own sort methods which ultimately still uses the compareTo() for comparison.
You can take a look on the subtle differences between Comparable vs Comparator here: What is the difference between compare() and compareTo()?
I think it is also worth mentioning that, by default Java compares String (objects) in a lexicographical order if you did not override the compareTo() method.
I would advocated that readability must be a primer for us as developers.
Apache Commons Lang (commons-lang) provides a simple fluent utility which reads a lot clearer:
if (is(obj1).greaterThan(obj2)) {
// do something
}
Note: is is shorthand for ComparableUtils.is which can be imported the following this static import statement:
import static org.apache.commons.lang3.compare.ComparableUtils.is;
When I try to implement my own ImmutableList (actually a wrapper that delegates to the underlying list) I get the following compiler error:
ImmutableListWrapper is not abstract and does not override abstract method isPartialView() in com.google.common.collect.ImmutableCollection
But in fact, it seems to be impossible to override isPartialView() because it is package protected and I'd like to declare the wrapper in my own package.
Why don't I simply extend ImmutableCollection? Because I want ImmutableList.copyOf() to return my instance without making a defensive copy.
The only approach I can think of is declaring a subclass in guava's package which changes isPartialView() from package-protected to public, and then having my wrapper extend that. Is there a cleaner way?
What I am trying to do
I am attempting to fix https://github.com/google/guava/issues/2029 by creating a wrapper that would delegate to the underlying ImmutableList for all methods except spliterator(), which would it override.
I am working under the assumption that users may define variables of type ImmutableList and expect the the wrapper to be a drop-in replacement (i.e. it isn't enough to implement List, they are expecting an ImmutableList).
If you want your own immutable list but don't want to implement it, just use a ForwardingList. Also, to actually make a copy, use Iterator as parameter for the copyOf. Here's a solution that should fulfill all your requirements described in the question and your answer.
public final class MyVeryOwnImmutableList<T> extends ForwardingList<T> {
public static <T> MyVeryOwnImmutableList<T> copyOf(List<T> list) {
// Iterator forces a real copy. List or Iterable doesn't.
return new MyVeryOwnImmutableList<T>(list.iterator());
}
private final ImmutableList<T> delegate;
private MyVeryOwnImmutableList(Iterator<T> it) {
this.delegate = ImmutableList.copyOf(it);
}
#Override
protected List<T> delegate()
{
return delegate;
}
}
If you want different behavior than ImmutableList.copyOf() provides, simply define a different method, e.g.
public class MyList {
public static List<E> copyOf(Iterable<E> iter) {
if (iter instanceof MyList) {
return (List<E>)iter;
return ImmutableList.copyOf(iter);
}
}
Guava's immutable classes provide a number of guarantees and make a number of assumptions about how their implementations work. These would be violated if other authors could implement their own classes that extend Guava's immutable types. Even if you correctly implemented your class to work with these guarantees and assumptions, there's nothing stopping these implementation details from changing in a future release, at which point your code could break in strange or undetectable ways.
Please do not attempt to implement anything in Guava's Imutable* heirarchy; you're only shooting yourself in the foot.
If you have a legitimate use case, file a feature request and describe what you need, maybe it'll get incorporated. Otherwise, just write your wrappers in a different package and provide your own methods and guarantees. There's nothing forcing you, for instance, to use ImmutableList.copyOf(). If you need different behavior, just write your own method.
Upon digging further, it looks like this limitation is by design:
Quoting
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableList.html:
Note: Although this class is not final, it cannot be subclassed as it has no public or protected constructors. Thus, instances of this type are guaranteed to be immutable.
So it seems I need to create my wrapper in the guava package.
The code my team is working on has several classes where equals and hashCode are not defined in the class hierarchy. We'd like to implement Comparable such that compareTo is consistent with equals using hashCode, like so:
class MyClass implements Comparable<MyClass>
{
private String myProperty;
// Other properties, etc.
....
public int compareTo(MyClass obj) {
// Natural ordering comparisons
...
// Reach here if natural ordering properties are equivalent
return new Integer(this.hashCode()).compareTo(new Integer(obj.hashCode());
}
}
Is this considered a valid means of implementing Comparable? Are there any pitfalls with using the default hashCode implementation that I should be aware of?
UPDATE: The behavior we're striving for is as follows:
The class properties are compared first, in a natural ordering we define.
If a given property for the two objects are equivalent, we move on to the next one in the ordering.
If all properties are equivalent, we return 0 only if this.equals(obj).
Yes this is a valid way. Apparently you want a fixed ordering for objects which are equal on other values (am I right? You did not explain your aim with the hashcode usage here).
The only thing i would do is copy the java code of Integer.compareTo() in your compareTo method, so you do not have to create 2 Integers for every comparison.
No, This is not the valid means of implementing Comparable. Because , suppose your all natural ordering comparison for two different objects of MyClass within equals method comes true , after that when hashcode of two objects are compared it would return false . This is so because in this case hashcode method of Object class would be called by default(as you have not provided your own hashcode method), Which will be different for different objects. Hence the two objects of MyClass will never be equal no matter if all natural ordering comparison comes out to be true.
While doing some casual reading I came across an interesting quote by Scott Meyers
Anytime you find yourself writing
code of the form "if the object is of
type T1, then do something, but if
it's of type T2, then do something
else," slap yourself.
I was just wondering why Java has "instance of" operator when you could do the same thing by overridden methods? When is it actually used?
Sometimes you have to use objects whose behavior (e.g. source code) you do not control so you cannot always rely on object-oriented solutions to type-related matters. (Especially consider that authors of libraries cannot anticipate every use case you might have; of course, you could argue that extension and implementation provide workarounds but they require much more effort than direct type checking.)
The "instanceof" operator gives you a way to inspect the type of an object and act conditionally.
It's ideal to avoid it, but sometimes necessary.
Use of instanceof can interfere with the Open/Closed Principle (the "O" in SOLID). If you implement instanceof tests, then your class may need to be modified as new implementation classes are created.
However, it is sometimes necessary. For example, it can be used in implementations of the Object.equals() method. The argument is an Object -- so that the method may be overridden by arbitrary subclasses -- but you usually need to cast it to your class's type to compare.
I actually use it when I'm using a 3rd party library and classes are final (the jerks!).
An if-type-do-something in code is a sign that the do-something should be a method defined in the class or interface with overriding behavior. But that assumes you control the implementation. Sometimes you don't.
When I'm implementing equals() for a class Foo it often looks like this:
public boolean equals(Object o) {
if (o instanceof Foo) {
Foo that = (Foo) o;
[ compare this to that ]
} else {
return false;
}
Since I'm overriding equals the signature is forced on me, but I need to know whether I have an instance of Foo or not for a meaningful comparison.
For example :
public void eat(Eatable eatable){
if(eatable instanceof fruit){
//direct eat
}
}
class Eatable {
}
class Fruit extends Eatable {
}
While writing complicated class structure like in Wrapper design pattern, you never know what kind of object u will encounter. In these situation you check the object with instance of operator.
I was re-reading Effective Java (2nd edition) item 18, prefer interfaces to abstract classes. In that item Josh Bloch provides an example of a skeletal implementation of the Map.Entry<K,V> interface:
// Skeletal Implementation
public abstract class AbstractMapEntry<K,V>
implements Map.Entry<K,V> {
// Primitive operations
public abstract K getKey();
public abstract V getValue();
// ... remainder omitted
}
Two questions stem from this example:
Why are getKey and getValue explicitly declared here as abstract methods? They are part of the Map.Entry interface, so I don't see a reason for the redundant declaration in the abstract class.
Why use the idiom of leaving these primitives methods, as Mr. Bloch refers to them, as abstract? Why not just do this:
// Skeletal Implementation
public abstract class AbstractMapEntry
implements Map.Entry {
private K key;
private V value;
// Primitive operations
public K getKey() {return key;}
public V getValue() {return value;}
// ... remainder omitted
}
The benefits of this are that each subclass doesn't have to define its own set of fields, and can still access the key and value by their accessors. If a subclass truly needs to define its own behavior for the accessors, it can implement the Map.Entry interface directly. The other downside is that in the equals method provided by the skeletal implementation, the abstract accessors are called:
// Implements the general contract of Map.Entry.equals
#Override public boolean equals(Object o) {
if (o == this)
return true;
if (! (o instanceof Map.Entry))
return false;
Map.Entry<?,?> arg = (Map.Entry) o;
return equals(getKey(), arg.getKey()) &&
equals(getValue(), arg.getValue());
}
Bloch warns against calling overridable methods (item 17) from classes designed for inheritance as it leaves the superclass vulnerable to changes made by subclasses.
Maybe this is a matter of opinion, but I was hoping to determine whether there's more to the story, as Bloch doesn't really elaborate on this in the book.
I would say it helps emphasize what the concrete class is intended to deal with, instead of just leaving it up to the compiler to tell you (or you having to compare both to see what is missing). Kind of self-documenting code. But it certainly isn't necessary, it is more of a style thing, as far as I can see.
There is more significant logic in returning these values than simple getter and setting. Every class I spot checked in the standard JDK(1.5) did something non-simple on at least one of the methods, so I would guess that he views such an implementation as too naive and it would encourage subclasses to use it instead of thinking through the problem on their own.
Regarding the issue with equals, nothing would change if the abstract class implemented them because the issue is overridable. In this case I would say that the equals is attempting to be carefully implemented to anticipate implementations. Normally equals in general should not be implemented to return true between itself and its subclass (although there are plenty that do) due to covariance issues (the superclass will think it equals the subclass, but the subclass won't think it equals the superclass), so this type of implementation of equals is tricky no matter what you do.
Bloch warns against calling
overridable methods (item 17) from
classes designed for inheritance as it
leaves the superclass vulnerable to
changes made by subclasses
He warns about calling overridable methods in the constructor, not in other methods.
One reason that AbstractMapEntry#getKey and getValue are abstract (i.e. unimplemented) is that Map.Entry is an inner interface to Map. Using nested classes/interfaces is how Java implements composition. The idea in composition is that the composed part is not a first-class concept. Rather, the composed part only make sense if it is contained in the whole. In this case, the composed part is Map.Entry and the root object of the composite is Map. Obviously the concept expressed is that a Map has many Map.Entrys.
Therefore the semantics of AbstractMapEntry#getKey and getValue will depend essentially on the implementation of Map that we're talking about. A plain old getter implementation as you've written will work just fine for HashMap. It won't work for something like ConcurrentHashMap which demands thread-safety. It's likely that ConcurrentHashMap's implementation of getKey and getValue make defensive copies. (Recommend checking the source code for yourself).
Another reason not to implement getKey and getValue is that the characters that implement Map are radically different ranging from ones that should have never belonged (i.e. Properties) to completely different universes from an intuitive impls of Map (e.g. Provider, TabularDataSupport).
In conclusion, not implementing AbstractMapEntry#getKey and getValue, because of this golden rule of API design:
When in doubt, leave it out (see here)
I don't see any reason
Allows the implementation to define how the key and value are stored.