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).
Related
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.
I have an ArrayList that I want to print in decimal and binary format.
Current output: decimal: S:2 S:3 S:3 S:3 S:1 S:2
Expected:
decimal: 2 3 3 3 1 2
binary : 10 11 11 11 1 10
Any help is appreciated on how I can accomplish this.
I get this error "Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method toBinaryString(int) in the type Integer is not applicable for the arguments (List)at generics.ExampleGenerics.main(ExampleGenerics.java:50)"
I am learning generics, do I need to cast an int to the string array to get this to work? or am I way off?
public class ExampleGenerics {
public static void main(String[] args) {
List < Square > squareList = new ArrayList < > (Arrays.asList(new Square(1),
new Square(2), new Square(2), new Square(3), new Square(3), new Square(3)));
System.out.println("original squareList: " + squareList);
Collections.rotate(squareList, -2);
System.out.println("rotated list: " + squareList);
System.out.println(Integer.toBinaryString(squareList)); //error
}
}
public class Square {
private int side;
public Square(int side) {
this.side = side;
}
public int getSide() {
return side;
}
public void setSide(int side) {
this.side = side;
}
#Override
public String toString() {
return "S:" + side;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + side;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Square))
return false;
Square other = (Square) obj;
if (side != other.side)
return false;
return true;
}
}
The issue is that you're attempting to pass your List to the method Integer.toBinaryString(). However, this method doesn't take Lists, it takes ints. This is stated in the exception: "The method toBinaryString(int) in the type Integer is not applicable for the arguments (List)".
Instead of passing in your List, you need to loop through it and pass in the int for each Square object. So instead of doing this:
System.out.println(Integer.toBinaryString(squareList));
Do this:
for(Square square:squareList){
System.out.println(Integer.toBinaryString(square.getSide()));
}
I am overriding equals and hashCode in a class that includes double fields. My first approach was to use the epsilon test in the equals method, and Double.hashCode( double ) in hashCode, but that can result in equal objects having different hash codes; here is a simplified example:
public class DoubleHashTest2
{
public static void main(String[] args)
{
double base1 = .9;
double base2 = .7;
Test test1 = new Test( base1 - .1 );
Test test2 = new Test( base2 + .1 );
System.out.println( test1.equals( test2 ) );
System.out.println( test1.hashCode() );
System.out.println( test2.hashCode() );
}
private static class Test
{
private double dnum1;
public Test( double dnum1 )
{
this.dnum1 = dnum1;
}
public boolean equals( Test other )
{
final double epsilon = .0001;
boolean result = false;
if ( this == other )
result = true;
else if ( other == null )
result = false;
else
result = Math.abs( this.dnum1 - other.dnum1 ) < epsilon;
return result;
}
public int hashCode()
{
int hash = Double.hashCode( dnum1 );
return hash;
}
}
}
I've thought of several solutions, including converting to BigDecimal, but I'm not really happy with any of them. I finally settled on rounding:
public boolean equals( Test other )
{
boolean result = false;
if ( this == other )
result = true;
else if ( other == null )
result = false;
else
{
double test1 = round( dnum1 );
double test2 = round( other.dnum1 );
result = test1 == test2;
}
return result;
}
public int hashCode()
{
double temp = round( dnum1 );
int hash = Double.hashCode( temp );
return hash;
}
private double round( double dnum )
{
// tests for NaN and +/-infinity omitted for brevity
final int places = 4;
final double round_const = Math.pow( 10, places );
double result = ((int)(dnum * round_const + .5)) / round_const;
return result;
}
But choosing a good rounding algorithm is difficult, and this seems kind of expensive. I looked at similar classes, such as Point2D.Double, but equals in this class fails, for example, when comparing .8 and 0.7999999999999999.
Is there a recommended way for dealing with this issue?
Answering the main question
You don't need any custom rounding, as Double class has doubleToLongBits() method, which simply converts double to long (both of them are 64-bit values).
Also, for your equals() method, you can compare two double values with Double#compare().
Possible equals() and hashCode() for your example:
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (null == other
|| this.getClass() != other.getClass()) {
return false;
}
return Double.compare(this.dnum1, ((Test) other).dnum1) == 0;
}
public int hashCode() {
long bits = Double.doubleToLongBits(this.dnum1);
return (int) (bits ^ (bits >>> 32));
}
About floating point arithmetic
Your example shows the disadvantage of double usage for floating point calculations - even values with the same magnitude can give close, but different results. Maybe you should use BigDecimal?
Also, see this question answers.
How about this?
public static boolean equals( double param1, double param2 )
{
final double epsilon = 1e-10;
// accounts for 0, NaN, +/-INFINITY
boolean result = param1 == param2;
if ( !result )
{
double quot = param1 / param2;
result = quot > 0 && (1 - quot) < epsilon;
}
return result;
}
To demonstrate:
public static void main(String[] args)
{
double dvar1 = 0.7 + 0.1;
double dvar2 = 0.9 - 0.1;
System.out.println( dvar1 == dvar2 ); // expect false
System.out.println( equals( dvar1, dvar2 ) ); // expect true
}
#Override
public int hashCode() {
return Double.hashCode(Math.round(dnum1));
}
public boolean equals( Object other )
{
if(other instanceof Test)
return equals(test);
return false;
}
public boolean equals( Test other )
{
if(other == null)
return false;
return isEqual(dnum1,other.dnum1);
}
public boolean isEqual(double number,double anotherNumber){
if (number == anotherNumber)// eg 0, NaN, +/-INFINITY
return true;
return Math.abs(number - anotherNumber) <= EPSILON;
}
Im having a class Woning (house) and a subclass KoopWoning (buyable House) and a subclass HuurWoning (rentable House). KoopWoning and Huurwoning extend Woning. HuurWoning is just a Woning, whereas KoopWoning has an extra variable energylevel. KoopWoning has also a function getEnergylevel, which returns the energylevel of the KoopWoning. I also have a class Portefeuille which has an arraylist of Woningen.
Im reading all Woningen in a Portefeuille from a textfile. In a 5th class, I want to be able to sort the ArrayList of Woningen of Portefeuille (from the textfile). I have a function woningenTot(int maxprijs) which returns an ArrayList with all the Woningen that fullfil the requirement (having a price below maxprijs). These Woningen I want to print on the screen.
The problem is as follows:
It can be possible that there is also a KoopWoning in the file. In that case I also want to be able to sort on energylevel. However, I can't sort on the energylevels. I can't call the function getEnergylevel because it's an ArrayList, and Woning doesn't contain the function getEnergylevel.
So how can I solve this? If it's too vague, I could include the code, however it's quite big :O
Any help is appreciated; i have spent a couple of hours on this program, from which at least 1.5 hours on this problem alone :(
EDIT: Here is the code for class KoopWoning
public class KoopWoning extends Woning implements EnergiepeilWoning {
private char energiepeil;
public KoopWoning (Adres adres, int kamers, int vraagPrijs, char energiepeil) {
super(adres, kamers, vraagPrijs);
this.energiepeil = energiepeil;
}
public char getEnergiepeil () {
return energiepeil;
}
public boolean compareEnergiepeil (Object other) {
boolean res = false;
if (other instanceof KoopWoning) {
KoopWoning that = (KoopWoning) other;
res = (this.getEnergiepeil() == that.getEnergiepeil());
}
return res;
}
public String toString () {
String res = adres + ", " + kamers + " kamers, prijs " + prijs + ", energiepeil " + energiepeil;
return res;
}
And here is the code for class Woning
public class Woning {
protected int kamers;
protected int prijs;
protected Adres adres;
protected String tag;
public Woning (Adres adres, int kamers, int prijs) {
this.adres = adres;
this.kamers = kamers;
this.prijs = prijs;
}
public String toString () {
String res = adres + ", " + kamers + " kamers, prijs " + prijs;
return res;
}
public void setTag (String tag) {
this.tag = tag;
}
public String getTag () {
return tag;
}
public boolean kostHooguit (int maxprijs) {
return (prijs <= maxprijs);
}
public boolean equals (Object other) {
boolean res = false;
if (other instanceof Woning) {
Woning that = (Woning) other;
if (this.adres.equals(that.adres))
res = true;
}
return res;
}
public static Woning read (Scanner sc) {
try {
Adres adress = Adres.read(sc);
int kamer = sc.nextInt();
sc.next();
sc.next();
int prijs = sc.nextInt();
String check = sc.next();
if (check.equals("energiepeil")) {
char peil = sc.next().charAt(0);
KoopWoning kwoning = new KoopWoning (adress, kamer, prijs, peil);
return kwoning;
}
else {
Woning woning = new Woning (adress, kamer, prijs);
return woning;
}
}
catch (Exception e) {
System.out.println("Woning: Exception is caught");
System.out.println(e.getMessage());
Adres adress = new Adres ("", "", "", "");
Woning woning = new Woning (adress, 0, 0);
return woning;
}
}
}
And lastly, the code for the class Portefeuille
public class Portefeuille {
private ArrayList<Woning> woninglijst;
public Portefeuille () {
woninglijst = new ArrayList<Woning>();
}
public void voegToe (Woning woning) {
if (!woninglijst.contains(woning))
woninglijst.add(woning);
}
public ArrayList<Woning> woningenTot (int maxprijs) {
ArrayList<Woning> woninglijst2 = new ArrayList<Woning>();
for (int i = 0; i < woninglijst.size(); i++) {
if(woninglijst.get(i).kostHooguit(maxprijs))
woninglijst2.add(woninglijst.get(i));
}
return woninglijst2;
}
public String toStringExt () {
String res = "[";
for (int i = 0; i < woninglijst.size(); i++)
res = res + woninglijst.get(i).toString() + "; ";
if (woninglijst.size() != 0)
res = res.substring (0, res.length() - 2);
res = res + "]";
return res;
}
public String toString () {
String res = "";
for (int i = 0; i < woninglijst.size(); i++)
res = woninglijst.get(i).toString2();
return res;
}
public boolean equals (Object other) {
boolean res = false;
if (other instanceof Portefeuille) {
Portefeuille that = (Portefeuille) other;
if (this.woninglijst.size() == that.woninglijst.size()) {
int i = 0;
while (i < this.woninglijst.size() && this.woninglijst.get(i).equals(that.woninglijst.get(i)))
i = i + 1;
res = (i == this.woninglijst.size());
}
}
return res;
}
public static Portefeuille read (String infile) {
try {
Scanner sc = new Scanner (new File(infile));
ArrayList<Woning> wlijst = new ArrayList<Woning>();
Portefeuille p = new Portefeuille();
int woningen = sc.nextInt();
int i = 0;
while (i < woningen) {
sc.nextLine();
String tag = sc.nextLine();
wlijst.add(Woning.read(sc));
p.voegToe(wlijst.get(i));
i++;
}
sc.close();
return p;
}
catch (Exception e) {
System.out.println("Portefeuille: Exception is caught");
Portefeuille p = new Portefeuille();
return p;
}
}
}
EDIT
I fixed it myself. Thanks for answering you all :)
You could define, on the top-level class, a method like getSortableValue(), and implement it to return a default field (you didn't mention the field you need to sort on for Woningen). In the KoopWoning you override this method to return the energyLevel instead. Then you always sort on the value returned by getSortableValue().
You can let the them implement Comparable, so like Woning implements Comparable<Woning>. This will let you implement the (required) method:
#override
public int compareTo(Woning other) {
int result = Integer.compareto(maxPrijs, other.maxPrijs);
if (result != 0) return result;
result = Integer.compareto(someField, other.someField);
if (result != 0) return result;
// etc...
return 0;
}
The subclass KoopWoning extends Woning implements Comparable<KoopWoning> can have a method like this:
#override
public int compareTo(KoopWoning other) {
int result = Integer.compareto(energylevel, other.energylevel);
if (result != 0) return result;
return super.compareTo(other);
}
Then all you need to do is load all the Woning instances in a list and execute
Collections.sort(list);
Having subclasses inherit Comparable is optional, so HuurWoning will just sort like Woning.
You could define a Comparator on Woning that determines the relative ordering of two Woning. You could do this either by having a method that looks at the actual types of the two arguments and then acts appropriately, or, better, by having an overrideable method of Woning that returns some value that you can use for sorting purposes.
If, for instance, you decide that anything with an energy level should come after anything without one, then you can have KoopWoning return something with the energy level in the high order bits of a long, so that it always comes out higher than anything without one (essentially you'd be setting a default energy level of zero).
Then, you can use
Collections.sort(arrayList, myComparator);
to sort the list based on the Comparator you've created.
There are some nice classes in the Guava library that help with Comparator building on multiple keys, but if your case is fairly simple, you probably won't need them.
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.