How to compare both strings and float in compareTo - java

I am trying to compare both strings and float in the compareTo method but I'm not sure what my final value is going to be.
Below is the compareTo method that I have implemented so far:
ObjectClass otherObj = (ObjectClass)o;
float f1 = this.getValue();
float f2 = otherObj.getValue();
int retValue = Float.compare(f1,f2);
String code1 = this.getCode();
String code2 = otherObj.getCode();
int retValue2 = code1.compareTo(code2);
int finalRet = ??
return finalRet;
if the input is
hashMap.put(new ObjectClass ("20030122", 0.019f), "20030122");
hashMap.put(new ObjectClass ("20030123", 0.019f), "20030123");
hashMap.put(new ObjectClass ("20030124", 0.011f), "20030124");
my output should be in this order
"20030123", 0.019f
"20030122", 0.019f
"20030124", 0.011f

In order to allow your class to be comparable you must implement in it interface Comparable
When the comparison should be based on more then single class member. You compare it sequentially when result of previous was equal to zero. By sequence order you specify the final ordering.
class MyObject implements Comparable<MyObject> {
String message;
long value;
#Override
public int compareTo(MyObject that) {
if(that == null) {
return -1;
}
if(this == that) {
return 0;
}
int result = this.message.compareTo(that.message);
if(result == 0) {
result = Long.compare(this.value,that.value);
}
return result;
}
}
The above example will result with
"20030122", 0.019f
"20030123", 0.019f
"20030124", 0.011f

Related

How to check in jUnit the equality of objects with double fields

We all know how to correctly check for fractional numbers in tests (using TOLERANCE):
class OxygenTankTest {
static final double TOLERANCE = 0.001;
#Test
void testFilling() {
OxygenTank tank = OxygenTank.withCapacity(100);
tank.fill(5.8);
tank.fill(5.6);
Assertions.assertEquals(0.114, tank.getStatus(), TOLERANCE);
}
}
But my question is how to check if we need to check not the individual values - but whole objects.
For example:
Need to test Summer - which performs the summation of fields
public class Summer {
public void setSum(Item itemTo, Item itemFrom) {
itemTo.setDiameter(itemTo.getDiameter() + itemFrom.getDiameter());
itemTo.setLength(itemTo.getLength() + itemFrom.getLength());
}
}
public class Item {
private Double diameter;
private Double length;
public Item(Double diameter, Double length) {
this.diameter = diameter;
this.length = length;
}
public Double getDiameter() {
return diameter;
}
public void setDiameter(Double diameter) {
this.diameter = diameter;
}
public Double getLength() {
return length;
}
public void setLength(Double length) {
this.length = length;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Item item = (Item) o;
if (diameter != null ? !diameter.equals(item.diameter) : item.diameter != null) return false;
return length != null ? length.equals(item.length) : item.length == null;
}
#Override
public int hashCode() {
int result = diameter != null ? diameter.hashCode() : 0;
result = 31 * result + (length != null ? length.hashCode() : 0);
return result;
}
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("Item{");
sb.append("diameter=").append(diameter);
sb.append(", length=").append(length);
sb.append('}');
return sb.toString();
}
}
How i try to write a test:
public class SummerTest {
#Test
public void setSum() {
Summer summer = new Summer();
Item itemFrom = new Item(2.321, 1.111);
Item itemTo = new Item(0.999, 0.999);
summer.setSum(itemFrom, itemTo);
// expected
Item expectedItem = new Item(3.32, 2.11);
assertThat(itemFrom, equalTo(expectedItem));
}
}
But it does not work!
java.lang.AssertionError:
Expected: <Item{diameter=3.32, length=2.11}>
but: was <Item{diameter=3.3200000000000003, length=2.11}>
Expected :<Item{diameter=3.32, length=2.11}>
Actual :<Item{diameter=3.3200000000000003, length=2.11}>
<Click to see difference>
How to properly check for compliance?
You overwrote the equals method that checks for exact equality. If you have objects that contain floating point values (float, double) that are considered in your equals implementation, you will want to not compare the object itself, but the values within the object:
assertEquals(expected.getDiameter(), itemFrom.getDiameter(), TOLERANCE);
assertEquals(expected.getLength(), itemFrom.getLength(), TOLERANCE);
Or if you want to get fancy you can create your own Matcher that goes into the assertThat.
Consider changing the set up of the test to allow for exact comparisons via Item::equals:
private static final double ITEM_FROM_DIAMETER = 2.321;
private static final double ITEM_FROM_LENGTH = 1.111;
private static final double ITEM_TO_DIAMETER = 0.999;
private static final double ITEM_TO_LENGTH = 0.999;
Item itemFrom = new Item(ITEM_FROM_DIAMETER, ITEM_FROM_LENGTH);
Item itemTo = new Item(ITEM_TO_DIAMETER, ITEM_TO_LENGTH);
Item expectedItem = new Item(ITEM_FROM_DIAMETER + ITEM_TO_DIAMETER, ITEM_FROM_LENGTH + ITEM_TO_LENGTH);
Also, since Item is mutable, it would be a good idea to assert itemFrom was not changed.

Java map value comparisons

This could be the entirely wrong usage for the datatype, but I'm trying to create a Map-Set of some sort, so before insertion into the map I'm trying to use
//Material is custom class
Map<Integer, Material> x = TreeMap();
if(!x.containsValue(new Material))
x.put(int val, new Material);
My expectation of this is that it would compare two objects generated from the same data would return true, but it appears that this is not the case. Why is that, and is there an existing solution other than iterating through the entire map to find out if any element contains a Material where all fields are the same as the incoming?
Having a well defined class Material
public class Material extends Comparable<Material> {
final int a;
final String b;
...
public Material(int a, String b, ...) {
this.a = a;
this.b = b;
}
#Override
int compareTo(Material other) {
int cmp = Integer.compare(a, other.a);
if (cmp == 0) {
cmp = b.compareTo(other.b);
}
...
return cmp;
}
#Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Material)) {
return false;
}
return compareTo((Material) other) == 0;
}
#Override int hashCode() {
return ...;
}
A Set suffices:
Set<Material> materials = new HashSet<>(); // hashCode+equals
Set<Material> materials = new TreeSet<>(); // compareTo
Now I have made the fields of Material final so the object is immutable, as changing would play havoc with the sets ordering.
For a mutable quality, like quantity:
Map<Material, Integer> stock = new HashMap<>();
Material material = new Material(...);
stock.put(material, 100);
int quantity = stock.getOrDefault(material, 0); // Java 8
int quantity = 0; // Java 7
{
Integer q = stock.get(material);
if (q != null) {
quantity = q;
}
}

Interesting HashMap implementation (build 1.7.0_25-b17)

I have developed a garbage collector friendly String cache for my Android game. Its purpose is to handle Strings for ints. I made a silly mistake implementing it but the bug never disclosed itself in desktop. In Android, however, the cache started returning funny Strings at once:
class IntStringCache {
private final Map<IntStringCache.IntCacheKey, String> cachedStrings = new HashMap<IntStringCache.IntCacheKey, String>();
private final IntCacheKey tempIntCacheKey = new IntCacheKey(0);
public String getStringFor(int i) {
tempIntCacheKey.setIntValue(i);
String stringValue = cachedStrings.get(tempIntCacheKey);
if (stringValue == null) {
stringValue = String.valueOf(i);
// ERROR - putting the same object instead of new IntCachKey(i)
cachedStrings.put(tempIntCacheKey, stringValue);
}
return stringValue;
}
public int getSize() {
return cachedStrings.size();
}
private class IntCacheKey {
private int intValue;
private IntCacheKey(int intValue) {
this.intValue = intValue;
}
private void setIntValue(int intValue) {
this.intValue = intValue;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + intValue;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IntCacheKey other = (IntCacheKey) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (intValue != other.intValue)
return false;
return true;
}
private IntStringCache getOuterType() {
return IntStringCache.this;
}
}
And the tests all of which pass:
public class IntStringCacheTest {
private IntStringCache intStringCache = new IntStringCache();
#Test
public void shouldCacheString() {
// given
int i = 1;
// when
String s1 = intStringCache.getStringFor(i);
String s2 = intStringCache.getStringFor(i);
// then
assertThat(s1).isNotNull();
assertThat(s1).isEqualTo(String.valueOf(i));
assertThat(s1).isSameAs(s2);
}
#Test
public void shouldCacheTwoValues() {
// given
int i1 = 1;
int i2 = 2;
int expectedCacheSize = 2;
// when
String s1 = intStringCache.getStringFor(i1);
String s2 = intStringCache.getStringFor(i2);
// then
assertThat(intStringCache.getSize()).isEqualTo(expectedCacheSize);
assertThat(s1).isSameAs(intStringCache.getStringFor(i1));
assertThat(s2).isSameAs(intStringCache.getStringFor(i2));
}
}
Note:
assertThat(String.valueOf(1)).isSameAs(String.valueOf(1));
fails.
The fact that the second test passes is interesting as, with the bug, there should be one key in the map that gets updated. This may be explained with hashCode() that could make the same key go into two different buckets inside HashMap. But how is it possible that the same key (even if in two buckets) returns the same two Stings? It seems that even though there is a bug in the code the HashMap does the job correctly.
My Android Java implementation, on the other hand, returns wrong number Strings with this bug at once.
You should consider replacing this entire class with SparseArray or its Support Library equivalent SparseArrayCompat (if you need it on <3.0 devices) as they are specifically designed to map integers to objects in a memory efficient way.

custom HashMap-Key (Java) slows down performance extremely

this is my first question here, but i hope i will provide all the needed information.
If NOT, please let me know!
My Problem:
I tried to improve my backtracking-algorithm by adding a HashMap to store the already processed results. For this i created a own class for the key of that HashMap. In there i overwrote the .equals()- and .hashCode()- methods.
But if i try to put this key and it's value into the map, it is taking much time, so that the algorithm becomes even less efficient then the backtrack-algorithm without the map.
To solve that problem, i changed the HashMap-Key to String and addded a .toString()-method to my key-class. This works very fine and it is quite fast. (Strange thing: .toString().hashCode() produces a lot of negative values, but seems to work)
Now my Question:
Is it always slowing down that much, if you create your own key?
I tried to find a answer to that question on my own and the only thin i found was to change .hashCode() or playing with the parameters of the HashMap-Constructor.
I tried both and i exported the produced HashCodes for my test-environment and i did not find any duplicates, though i know, it isn't a "good" method for hash-codes!
Here is a copy of my HashKey-Class (names of variables and methods changed):
public class HashKey {
private final int int0, int1, int2;
public HashKey(int int0, int int1, int int2) {
this.int0 = int0;
this.int1 = int1;
this.int2 = int2;
}
public int getInt0() {
return this.int0;
}
public int getInt1() {
return this.int1;
}
public int getInt2() {
return this.int2;
}
#Override
public int hashCode() {
final int prime1 = 107;
final int prime2 = 227;
final int prime3 = 499;
int result = 1;
result = prime1 * result + this.int2;
result = prime2 * result + this.int1;
result = prime3 * result + this.int0;
return result;
}
#Override
public String toString() {
return "Int0: " + this.int0 + " Int1: " + int1 + " Int2: " + int2;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof HashKey) {
boolean eq0, eq1, eq2;
eq0 = this.int0 == ((HashKey) obj).getInt0();
eq1 = this.int1 == ((HashKey) obj).getInt1();
eq2 = this.int2 == ((HashKey) obj).getInt2();
if (eq0 && eq1 && eq2) {
return true;
}
}
return false;
}
}
And in my main-Class i use this:
HashMap<HashKey, List<Object>> storedResults = new HashMap<HashKey, List<Object>>();
int x1,x2,x3;
Object obj;
// later in a method:
storedResults.put(new HashKey(x1,x2,x3), obj);
If i change the Type of the Key to String and put that String into the Map, it works fine! So the HashKey.hashCode()-method and the rest of the algorithm works fine and is quite fast.
Does anybody know, what i can do to use this HashKey? For this algorithm it is not that important, but i want to know it for future algorithms!
If there are any questions or critics: they are VERY welcome!
Thanks in advance!
Klumbe
Try this:
Simplyfy your equals(..)-method and do not calculate the hashCode more than once.
public final class HashKey {
private final int int0, int1, int2;
private final int hashCode;
public HashKey(int int0, int int1, int int2) {
this.int0 = int0;
this.int1 = int1;
this.int2 = int2;
hashCode=107*int0+227*int1+499*int2;
}
#Override
public final int hashCode() {
return hashCode;
}
#Override
public final boolean equals( finalObject obj) {
if (!obj instanceof HashKey)
retun false;
HashKey other = (HashKey)obj;
return int0 == other.int0 && int1 == other.int1 && int2 == other.int2;
}
}
Referring to the comment of fge I changed the code.
Your class is nearly immutable: all your instance members are final, just the class itself would also need to be.
But as all your instance members are final, you could as well calculate the hash code at build time:
// Add as member:
private final int hashCode;
public HashKey(int int0, int int1, int int2) {
this.int0 = int0;
this.int1 = int1;
this.int2 = int2;
hashCode = // calculate hash code here
}
public int hashCode()
{
return hashCode;
}
By the way, negative hash codes are nothing to worry about. .hashCode() returns an int, after all.

compareTo() method java is acting weird

hi im having trouble getting this to work im getting an error here with my object comparison...how could I cast the inches to a string ( i never used compare to with anything other than strings) , or use comparison operators to compare the intigers,
Object comparison = this.inches.compareTo(obj.inches);
here is my code so far
import java.io.*;
import java.util.*;
import java.lang.Integer;
import java.lang.reflect.Array;
public class Distance implements Comparable<Distance> {
private static final String HashCodeUtil = null;
private int feet;
private int inches;
private final int DEFAULT_FT = 1;
private final int DEFAULT_IN = 1;
public Distance(){
feet = DEFAULT_FT;
inches = DEFAULT_IN;
}
public Distance(int ft, int in){
feet = ft;
inches = in;
}
public void setFeet(int ft){
try {
if(ft<0){
throw new CustomException("Distance is not negative");
}
}
catch(CustomException c){
System.err.println(c);
feet =ft;
}
}
public int getFeet(){
return feet;
}
public void setInches(int in){
try
{
if (in<0)
throw new CustomException("Distance is not negative");
//inches = in;
}
catch(CustomException c)
{
System.err.println(c);
inches = in;
}
}
public int getInches(){
return inches;
}
public String toString (){
return "<" + feet + ":" + inches + ">";
}
public Distance add(Distance m){
Distance n = new Distance();
n.inches = this.inches + m.inches;
n.feet = this.feet + m.feet;
while(n.inches>12){
n.inches = n.inches - 12;
n.feet++;
}
return n;
}
public Distance subtract(Distance f){
Distance m = new Distance();
m.inches = this.inches - f.inches;
m.feet = this.feet - f.feet;
while(m.inches<0){
m.inches = m.inches - 12;
feet--;
}
return m;
}
#Override
public int compareTo(Distance obj) {
// TODO Auto-generated method stub
final int BEFORE = -1;
final int EQUAL = 0;
final int AFTER = 1;
if (this == obj) return EQUAL;
if(this.DEFAULT_IN < obj.DEFAULT_FT) return BEFORE;
if(this.DEFAULT_IN > obj.DEFAULT_FT) return AFTER;
Object comparison = this.inches.compareTo(obj.inches);
if (this.inches == obj.inches) return compareTo(null);
assert this.equals(obj) : "compareTo inconsistent with equals";
return EQUAL;
}
#Override public boolean equals( Object obj){
if (obj != null) return false;
if (!(obj intanceof Distance)) return false;
Distance that = (Distance)obj;
( this.feet == that.feet &&
this.inches == that.inches);
return true;
else
return false;
}
#Override public int hashCode(int, int) {
int result = HashCodeUtil.inches;
result = HashCodeUtil.hash(result, inches );
result = HashCodeUtil.hash(result, feet);
ruturn result;
}
You're comparing object references. Try to compare object value; either override hashCode() or compare field values.
#Override
public int compareTo(Distance obj) {
....
if (this == obj) return EQUAL; <--- This
...
}
With this line:
Object comparison = this.inches.compareTo(obj.inches);
you are trying to dereference an int, a primitive type. The compiler should be giving you an error: you can only dereference Objects using the dot .
I'm not sure what you want this compareTo code to do, but it is at this point, to compare primitive types, that you should be using ==:
if (this.inches == obj.inches) return compareTo(null);
Be aware that in this line: if (this == obj) return EQUAL; you are comparing object references, which might or might not be what you want. Since your class doesn't override the equals method, this comparison is equivalent to this.equals(obj).

Categories