I've created a java dictionary using java.util.Hashtable with 2-tuple of strings as it's keys and int as values.
class pair<e,f>{
public e one;
public f two;
}
I used to above class to initialize a dictionary:
Dictionary<pair<String, String>, Integer> dict = new Hashtable();
Now I'm unable to check whether a key exists in dict, I mean I am unable to pass pair of strings as argument to dict.containsKey() method.
You need to implement hashCode and equals for stuff you want to use as Hashtable keys. If you don't do that, the default mechanism is used, and that will use object identity, not object equality (meaning two tuples are not considered equal even if they contain "equal" entries).
And the key fields should really be immutable, otherwise it can also break things.
Try something like this:
public class Pair<E, F> {
private final E e;
private final F f;
public Pair(E e, F f) {
this.e = e;
this.f = f;
}
public E getE() {
return e;
}
public F getF() {
return f;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Pair<E,F> other = (Pair<E,F>) obj;
if (!this.e.equals(other.getE())) {
return false;
}
if (!this.f.equals(other.getF())) {
return false;
}
return true;
}
#Override
public int hashCode() {
hash = 53 * e.hashCode() + f.hashCode();
return hash;
}
}
I've assumed that e and f is not null. If it can be null then you must check whether e == null before the if(e.equals(other.getE()) to prevent a NPE.
Further notes:
You should in almost all cases set members of a class to private
(except static members).
Proper Java convention is to have class names in CapitalizedWords.
Generic type parameters should be a single upper-case character.
Related
I have use TreeMap to store key value.
For key using custom object.
But once I have faced very strange issue, I am not able to get value which I have set earlier(with same key).
below is my code
public final class TestOptions implements Cloneable {
private Map<StorageSystemOptionKey, Object> options = new TreeMap<StorageSystemOptionKey, Object>();
private static final class StorageSystemOptionKey implements Comparable<StorageSystemOptionKey> {
/** Constant used to create hashcode */
private static final int HASH = 31;
private final Class<? extends StorageRepository> storageRepositoryClass;
/** The option name */
private final String name;
private StorageSystemOptionKey(Class<? extends StorageRepository> storageRepositoryClass, String name) {
this.storageRepositoryClass = storageRepositoryClass;
this.name = name;
}
public int compareTo(StorageSystemOptionKey o) {
int ret = storageRepositoryClass.getName().compareTo(o.storageRepositoryClass.getName());
if (ret != 0) {
return ret;
}
return name.compareTo(o.name);
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final StorageSystemOptionKey that = (StorageSystemOptionKey) o;
if (!storageRepositoryClass.equals(that.storageRepositoryClass)) {
return false;
}
if (!name.equals(that.name)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int result;
result = storageRepositoryClass.hashCode();
result = HASH * result + name.hashCode();
return result;
}
}
void setOption(Class<? extends StorageRepository> fileSystemClass, String name, Object value) {
options.put(new StorageSystemOptionKey(fileSystemClass, name), value);
}
Object getOption(Class<? extends StorageRepository> fileSystemClass, String name) {
StorageSystemOptionKey key = new StorageSystemOptionKey(fileSystemClass, name);
return options.get(key);
}
boolean hasOption(Class<? extends StorageRepository> fileSystemClass, String name) {
StorageSystemOptionKey key = new StorageSystemOptionKey(fileSystemClass, name);
return options.containsKey(key);
}
public int compareTo(TestOptions other) {
if (this == other) {
return 0;
}
int propsSz = options == null ? 0 : options.size();
int propsFkSz = other.options == null ? 0 : other.options.size();
if (propsSz < propsFkSz) {
return -1;
}
if (propsSz > propsFkSz) {
return 1;
}
if (propsSz == 0) {
return 0;
}
int hash = options.hashCode();
int hashFk = other.options.hashCode();
if (hash < hashFk) {
return -1;
}
if (hash > hashFk) {
return 1;
}
return 0;
}
#Override
public Object clone() {
TestOptions clone = new TestOptions();
clone.options = new TreeMap<StorageSystemOptionKey, Object>(options);
return clone;
}
}
calling method to set and get like
public abstract Class<? extends StorageRepository> getStorageRepositoryClass();
public Class<? extends StorageRepository> getStorageRepositoryClass() {
return MyImpl.class;
}
TestOptions opt =new TestOptions(); // shared accross all Threads
Object getProperty(String name) {
return opt.getOption(getStorageRepositoryClass(), name);
}
void setProperty(String name, Object value) {
opt.setOption(getStorageRepositoryClass(), name, value);
}
Using set and get method in multi-threaded application.
queries:
I am calling set/get in multiple time then also I was not able to get value which was set earlier(same key)
Is this due to Treeset implementation is not synchronized
or problem with hashCode, equals or compareTo method implementation?
On a quick glance your compareTo(), equals() and hashCode() look fine. Note that TreeMap will mostly use compareTo() to find elements so that method needs to be correct (your's looks technically correct).
However, TreeMap and TreeSet (as well as other basic collections and maps) are not thread-safe and thus concurrent modifications can cause all kinds of unexpected behavior. We once had a case where 2 threads were trying to add a single element to a hashmap and the threads ended up in an endless loop because the internal list to resolve clashes produced a cycle (due to the concurrent put).
So either use the ConcurrentXxxx maps and collections or synchronize access to yours.
TreeSet is not synchronized. I belive ConcurrentSkipListMap might be better.
Check also your hashCode, equals implementation
I am trying to Implement a class named Parade using an ArrayList, which will manage instances of class Clown. Each Clown needs to be identified by all object data String for their name, int id and double size. I join a new Clown to the end of the Parade. Only the Clown at the head of the Parade (i.e., the first one) can leave the Parade. In addition, I write a method called isFront that takes a Clown as parameter and returns true if the passed clown is at the front of the parade otherwise returns false. Create a test application to demonstrate building a parade of three or four clowns and include your own name. Then, remove one or two, and add another one or two. Also, test the isFront method by passing different clowns to the method.
I have a code but it is not returning true for the isFront method, I am trying to use contains method I also tried to use Comparable interface Clown but it did not work that well. Not sure what to do.
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
Parade circus = new Parade();
circus.addClown(new Clown("Bobby",9,12.0));
circus.addClown(new Clown("Clair", 2, 11.0));
circus.addClown(new Clown("Tony",6,10.0));
circus.addClown(new Clown("Sarah",3,5.0));
circus.display();
System.out.println(circus.isFront(new Clown("Bobby", 9, 12.0)));
}
}
import java.util.ArrayList;
public class Parade
{
private static ArrayList<Clown> parade;
private int top;
public Parade()
{
top=0;
parade= new ArrayList<Clown>();
System.out.println(parade);
}
public void addClown(Clown c)
{
parade.add(c);
top++;
}
public void removeClown() //(Clown c)
{
parade.remove(0);
top--;
}
public void display()
{
System.out.println(parade);
}
public void getData()
{
parade.get(0);
}
public void setData()
{
parade.set(1,new Clown("Claire",2,5.0));
System.out.println(parade);
}
public int getTop()
{
return top;
}
public boolean isFront(Clown c)
{
return !parade.isEmpty() && c.equals(parade.get(0));
}
//exceptions
}
public class Clown
{
private String name;
private int id;
private double size;
public Clown(String name, int id, double size)
{
this.name=name;
this.id=id;
this.size=size;
}
public String getName()
{
return name;
}
public int getId()
{
return id;
}
public double getSize()
{
return size;
}
public String toString()
{
return name.toString() + id + size;
}
public boolean equals(Object o) {
if (o instanceof Clown c) {
return this.getName().equals(c.getName()) && this.getId() == c.getId() && this.getSize() == c.getSize();
}
return false;
}
}
their is not much info in our textbook about this stuff Java FOundations 5th e Lewis like working with objects and arraylists it skips it and assumes you already know it lol..
Firstly, objects in Java are, by default, compared by reference. So, even if you create two Clown objects with the exact same properties, Java sees them as different objects because both those object references are not the same, they are both referring to different memory locations. You can override this behavior and ask Java to compare it as you want by overriding the equals() method of the Object class:
public class Clown {
private String name;
private int id;
private double size;
public Clown(String name, int id, double size) {
this.name=name;
this.id=id;
this.size=size;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public double getSize() {
return size;
}
#Override
public boolean equals(Object o) {
if (o instanceof Clown) {
Clown c = (Clown) o;
return this.getName().equals(c.getName());
}
return false;
}
#Override
public int hashCode() {
return this.getId();
}
#Override
public String toString() {
return name.toString() + id + size;
}
}
This will help with contains()(it internally uses equals()).
Secondly, you can just compare your clown with the first clown to see if it is the one at the front:
public boolean isFront(Clown c) {
return !parade.isEmpty() && c.equals(parade.get(0));
}
The isFront() method will return true if the parade is not empty and the clown c is equal to to the first clown in the parade. get(0) retrieves the first clown in the parade.
As per your comment, if you want that two clowns be equal only if all their properties are equal, change your equals method to:
#Override
public boolean equals(Object o) {
if (o instanceof Clown) {
Clown c = (Clown) o;
return this.getName().equals(c.getName()) &&
this.getId() == c.getId() &&
this.getSize() == c.getSize();
}
return false;
}
The equals() method is of the Object class which is the parent class of all Java classes. It defines how to compare two objects.
Its signature is as follows:
public boolean equals(Object obj)
As we're overriding, its signature must be the same in the derived class, in our case in class Clown. Its parameter is of type Object not Clown. Any type can be converted to Object, if I compare an object of Clown to another type, like:
Clown c = new Clown("X", 1, 10);
if ( c.equals(objectOfAnotherType) ) {..}
it will still work.
So we use the instanceof operator to check if that another object is also a Clown. If it is not an instance of Clown, we return false but if it is, we convert/cast that object to Clown, only then we can call getName() and other getter methods:
if (o instanceof Clown) {
Clown c = (Clown) o; //Casting happens here
return this.getName().equals(c.getName()) &&
this.getId() == c.getId() &&
this.getSize() == c.getSize();
}
return false;
Java 14 introduced a shortcut for this, instead of these steps:
if (o instanceof Clown) {
Clown c = (Clown) o;
we can simply write:
if (o instance of Clown c)
which does the casting for us and stores it in c.
Lastly, I have also overriden Object.hashCode() because you have to when you override equals(), here's why.
I'm using a java.util.Set interface with a java.util.HashSet implementation and storing it in a Map.
I add an object to a Set then retrieve the Set object again and am able to add another object that is equal to the first.
When adding the seemingly equal objects, Set.add returns true and two equal objects are stored in a HashSet. How is this possible and what can I do to fix this apparent breakage of the Set contract?
I'm using Java 12 via IntelliJ IDEA 2018.3.6 and have checked my java.lang.Object.hashCode implementation for the class of the two objects I add to the Set, with both returning the same hash code. I've also checked the java.lang.Objects.equals implementation and it returns true when the method is used to check their equality. Both objects are wrapped in another object, Entity, but that only forwards the objects' hashCode and equals implementations.
class Model {
...
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Offer)) {
return false;
}
Offer offer = (Offer) obj;
return Objects.equals(id, offer.id)
&& Objects.equals(name, offer.name)
;
}
#Override
public int hashCode() {
int result = 1;
result = 31 * result + Objects.hashCode(id);
result = 31 * result + Objects.hashCode(name);
return result;
}
...
}
class Store {
...
private static class Entry {
Object value;
Entry(Object value) {
this.value = value;
}
Object getValue() {
return value;
}
#Override
public boolean equals(Object obj) {
return Objects.equals(value, obj);
}
#Override
public int hashCode() {
return value.hashCode();
}
#Override
public String toString() {
return "Entry[value = " + value + "]";
}
}
...
private Map<Class<?>, Set<Entry>> data;
...
private Set<Entry> get(Class<?> type) {
return data.getOrDefault(type, new HashSet<>());
}
#Override
public void persist(Object obj) {
Entry entry = new Entry(obj);
Set<Entry> objects = get(obj.getClass());
if (objects == null) {
objects = new HashSet<>();
}
if (!objects.add(entry)) {
throw new ObjectExistsException
("Object already exists: " + obj);
}
data.put(obj.getClass(), objects);
}
...
}
When obj1 and obj2 of type Model are equal and objects already contains obj1 wrapped in an Entry object, I expect obj2 not to be added to objects when obj2 is wrapped in entry and for objects.add(entry) to return false then an ObjectExistsException to be thrown.
However, what actually is happening is objects.add(entry) returns true and obj2 wrapped in entity is being added to objects.
#Override
public boolean equals(Object obj) {
return Objects.equals(value, obj);
}
This isn't a correct implementation of Entry.equals. This potentially compares an Entry with the value held by the current entry. (Like comparing a letter with an envelope).
Make your equals method check that obj is an Entry, and get its value, and check equality to that.
You were right #Andy Turner, but it was #Andreas that pointed me in the right direction. I thought I would be lazy and not write a full equals method implementation, but it cost me. It should have been like this:
private static class Entry {
...
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Entry)) {
return false;
}
Entry entry = (Entry) obj;
return Objects.equals(getValue(), entry.getValue());
}
...
}
Thank you both.
I need to find a way to cache Methods(java.lang.reflect.Method) in such a way that whenever I call a function with the class (Class) methodName(String) and arguments(T[]) the function will return the cached method if exists or find the method, add it to the cache and return it.
I want to use HashMap for caching so I can find the method in O(1) but the problem is that I need to useisAssignableFrom when I override the equals method:
public class A1 extends AParent {}
public class A2 extends AParent {}
public class AParent {}
public class Temp{
public void testFunc(AParent a){}
}
This is the class I use for the keys in the HashMap :
import java.util.Arrays;
class MethodAbs{
Class c;
String methodName;
Class<?>[] argsTypes;
public MethodAbs(Class c, String methodName, Class<?>[] argsTypes){
this.c = c;
this.methodName = methodName;
this.argsTypes = argsTypes;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MethodAbs methodAbs = (MethodAbs) o;
if (c != null ? !c.equals(methodAbs.c) : methodAbs.c != null) return false;
if (methodName != null ? !methodName.equals(methodAbs.methodName) : methodAbs.methodName != null)
return false;
return isArgsTypesEq(argsTypes, methodAbs.argsTypes);
}
//a method is equals to the one cached if the arguments types
// can be cast to the ones that are saved on the map,
// i.e the ones on the method declaration
private boolean isArgsTypesEq(Class<?>[] at1, Class<?>[] at2){
boolean res = at1.length == at2.length;
for(int i = 0; i<at1.length && res; i++){
if(!at1[i].isAssignableFrom(at2[i])) res = false;
}
return res;
}
//default implementation (not working properly!)
#Override
public int hashCode() {
int result = c != null ? c.hashCode() : 0;
result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
result = 31 * result + Arrays.hashCode(argsTypes);
return result;
}
}
The class I use for caching
class Run{
public Map<MethodAbs, Method> map = new HashMap<>();
public<T> Method myFunc(Class c, String methodName, T[] args){
MethodAbs ma = new MethodAbs(c, methodName, getTypes(args));
if(map.containsKey(ma)){
return map.get(ma);
}
else{
for(Method method: c.getMethods()){
MethodAbs currMethodAbs = new MethodAbs(c, method.getName(), method.getParameterTypes());
if(!map.containsKey(currMethodAbs))
map.put(currMethodAbs, method);
if(currMethodAbs.equals(ma)) break;
}
}
return map.get(ma);
}
private<T> Class<?>[] getTypes(T[] args) {
Class<?>[] types = new Class<?>[args.length];
for(int i = 0; i< args.length; i++){
types[i] = args[i].getClass();
}
return types;
}
}
And Main:
public static void main(String[] args){
Run r = new Run();
Object [] arr = new Object[1];
arr[0] = new A1();
r.myFunc(Temp.class, "testFunc", arr);
arr[0] = new A2();
r.myFunc(Temp.class, "testFunc", arr);
}
In the scenario above after calling r.myFunc for the first time, the map looks like this:
MethodAbs(Temp.class, "testFunc", [AParent.class])
on the second time map.containsKey will return false(because AParent.hashCode != A2.hashCode) but they are equals.
The hierarchy shown in the example will not necessarily look like that(for example A2 can be a grandchild of AParent)
I know I can use the Class and method name as keys and the value will be a list of methods which I'll need to iterate and compare with equals but I'm trying to find a better way...
Unfortunately, you're equals method is fundamentally broken, for at least two reasons.
It is not symmetric, see the following code snippet:
public static void main(String... args) {
MethodAbs methodValueOfObject = new MethodAbs(String.class, "valueOf", new Class<?>[] { Object.class });
MethodAbs methodValueOfCharArrays = new MethodAbs(String.class, "valueOf", new Class<?>[] { char[].class });
System.out.println(methodValueOfObject.equals(methodValueOfCharArrays)); // prints "true"
System.out.println(methodValueOfCharArrays.equals(methodValueOfObject)); // prints "false"
}
It equates methods which you probably don't mean to be considered equal. To see that imagine that your Temp class has two testFunc methods, public void testFunc(A1 a) and public void testFunc(A2 a). The corresponding MethodAbs objects shouldn't be equal, but according to your implementation, they indeed are.
I think that the best solution for you is to just get rid of the cache altogether. Just use
public Method getMethod(Class<?> c, String methodName, Class<?>... paramClasses) {
try {
return c.getDeclaredMethod(methodName, paramClasses);
} catch (NoSuchMethodException | SecurityException e) {
// Your exception handling goes here
return null;
}
}
Class objects are already cached by the classloader, so the performance loss is negligible.
I need to check if an equivalent instance of a particular Object is in a List.
The Objects are instances of a Final Class that has an equals method that is too strict. I want to be able to provide a different implementation of equals to a "contains" method to check if the object is contained in the List.
The equals method in the class below will return false if the elements of partsInBox are in a different order; I need to change this behavior to be order indiscriminate.
public final class Box {
String category;
List<Integer> partsInBox;
#Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Box box = (Box) o;
return category.equals(box.category)
&& partsInBox.equals(box.partsInBox);
}
}
I would like to be able to do something like this:
List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for
boolean contained = contatins(boxes, box, new EqualsMethod() {
#Override
public boolean areEqual(Box b1, Box b2) {
if (b1 == b2) { return true; }
return b1.category.equals(b2.category)
&& b1.partsInBox.containsAll(b2.partsInBox);
}
});
What are my options for achieving this type of functionality?
The ideal solution would be changing the current behavior of the equals() method. However, it could be not possible for you if you don't have access to the other code.
Instead, you can use CollectionUtils.exists(collection, predicate) from Apache CollectionUtils.
http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/CollectionUtils.html
You can create a Predicate with the custom conditions you need to determine if your objects are equal enough.
Hope it helps.
Well since the class is final you can't extend it.
There is however the Comparator<T> interface which you could make use of, something like this:
public class BoxComparator implements Comparator<Box> {
#Override
public int compare(Box b1, Box b2) {
if (b1 == b2) { return 0; }
// return -1 or 0 or +1...
}
public static void main(String[] args) {
Box box1, box2;
...
boolean contains = new BoxComparator().compare(box1, box2) == 0;
}
}
I'm not completely sure from your code examples above if you want to compare a Box to another Box or a List<Box> - in the latter case you can't derive Comparator, but you could do something similar, for example a BoxInListComparator.
Hope this helps.
Equator.java
public interface Equator<T> {
boolean equals(T obj1, T obj2);
}
Some other class
public static <T> boolean contains(Collection<T> toSearch, T toSeek, Equator<T> equator) {
for (T oneItem : toSearch) {
if (equator.equals(oneItem, toSeek)) {
return true;
}
}
return false;
}
To use it
import static some.other.class.contains; // The contains method from the class above
List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for
boolean contained = contains(boxes, box, new Equator<Box>() {
#Override
public boolean equals(Box b1, Box b2) {
if (b1 == b2) { return true; }
return b1.category.equals(b2.category)
&& b1.partsInBox.containsAll(b2.partsInBox);
}
});
You could use a Comparator with Java's built-in methods for sorting and binary search. Suppose you have a class like this, where a and b are the fields you want to use for sorting:
class Thing { String a, b, c, d; }
You would define your Comparator:
Comparator<Thing> comparator = new Comparator<Thing>() {
public int compare(Thing o1, Thing o2) {
if (o1.a.equals(o2.a)) {
return o1.b.compareTo(o2.b);
}
return o1.a.compareTo(o2.a);
}
};
Then sort your list:
Collections.sort(list, comparator);
And finally do the binary search:
int i = Collections.binarySearch(list, thingToFind, comparator);
It would be easier (but not so self-evidently inefficient) in Groovy, using Closures. Well, here we go in Java:
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// ------- Original code with comments added
public final class Box {
// these should be final and List<Integer> should be immutable using
// Collections.unmodifiableList() to avoid nasty surpises, and should
// possibly be pre-sorted
String category;
List<Integer> partsInBox;
#Override
public boolean equals(Object o) {
// same instance, then true (works if null passed, too)
if (this == o) {
return true;
}
// Null and not exactly same class (instanceof not needed as "final"), then false
if (o == null || getClass() != o.getClass()) {
return false;
}
Box box = (Box) o;
// otherwise same category and exactly same list (including ordering)
return category.equals(box.category) && partsInBox.equals(box.partsInBox);
}
}
// ------- Create a wrapper class around Box, repainting the house
class WrappedBox {
final Box box;
WrappedBox(Box box) {
assert box != null;
this.box = box;
}
public String getCategory() {
return box.category;
}
public List<Integer> getPartsInBox() {
return box.partsInBox;
}
public boolean equals(Object o) {
// same instance, then true (works if null passed, too)
if (this == o) {
return true;
}
// Null and not same class, then false
if (o == null || !(o instanceof WrappedBox)) {
return false;
}
//
// otherwise same category and the set of b1 parts is a superset of the set of b2 parts
// this is not symmetric; should probably be a set comparison. What happens if there
// are several integers with the same value??
// return b1.category.equals(b2.category)
// && b1.partsInBox.containsAll(b2.partsInBox);
//
// SO RECODE AS AUXILIARY EXERCISE:
//
WrappedBox other = (WrappedBox)o;
if (!this.getCategory().equals(other.getCategory())) {
return false;
}
//
// You probably want to buffer these somehow:
//
List<Integer> x1 = new ArrayList(this.getPartsInBox());
List<Integer> x2 = new ArrayList(other.getPartsInBox());
Collections.sort(x1);
Collections.sort(x2);
return x1.equals(x2);
}
}
// --------- Now we can ask for "contains", though one should really create a
// ---------- List<WrappedBox> first if this happens often
class BoxHandler {
static boolean containsBox(List<Box> boxes, Box box) {
assert box != null;
assert boxes != null;
WrappedBox wbox = new WrappedBox(box);
for (Box cur : boxes) {
if (wbox.equals(new WrappedBox(cur))) {
return true;
}
}
return false;
}
}
You can't provide other method to make the comparation to the List. The best and most simple solution is to modify your equals() method. If you can't modify equals you can implement a Decorator class to create a list with the areEquals comparation that you need.
public class BoxList<E extends Box> implements List<E>{
private List<E> list;
public BoxList(List<E> list) {
this.list = list;
}
//Modify the behavior of the methods
#Override
public boolean contains(Object o) {
for(E element : list) {
if (element.areEquals(o)) {
return true;
}
}
return false;
}
// Redirect all other List methods to the original list
#Override
public boolean add(E e) {
return list.add(e);
}
#Override
public void add(int index, E element) {
list.add(index, element);
}
...