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.
Related
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 want to sort an Array of ArrayList by the first int of the ArrayLists elements.
I have tried to override the compare method of the Comparator class but it throws:
Exception in thread "main" java.lang.NullPointerException
at BikeGA$1.compare(BikeGA.java:515)
at BikeGA$1.compare(BikeGA.java:1)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:351)
at java.util.TimSort.sort(TimSort.java:230)
at java.util.Arrays.sort(Arrays.java:1438)
at BikeGA.main(BikeGA.java:512)
The code is:
int max_generations = 20;
static ArrayList<Integer>[] population = new ArrayList[max_generations];
Arrays.sort(population, new Comparator<ArrayList<Integer>>(){
#Override
public int compare(final ArrayList<Integer> entry1, final ArrayList<Integer> entry2){
return entry1.get(0).compareTo(entry2.get(0));
}
});
Can someone help me?
Thanks.
Your Comparator should handle null or empty ArrayLists in order for it to work with any data you put in your array :
#Override
public int compare(final ArrayList<Integer> entry1, final ArrayList<Integer> entry2){
if (entry1 == null && entry2 == null)
return 0;
if (entry1 == null)
return 1;
if (entry2 == null)
return -1;
if (entry1.isEmpty() && entry2.isEmpty())
return 0;
if (entry1.isEmpty())
return 1;
if (entry2.isEmpty())
return -1;
return entry1.get(0).compareTo(entry2.get(0));
}
This will put the null elements in the end of the array, and the empty lists before them.
You are comparing 2 arrays but you don't check if comparing object exists...
int max_generations = 20;
static ArrayList<Integer>[] population = new ArrayList[max_generations];
Arrays.sort(population, new Comparator<ArrayList<Integer>>(){
#Override
public int compare(final ArrayList<Integer> entry1, final ArrayList<Integer> entry2){
Integer value1 = entry1.get(0) == null : -1 ? entry1.get(0);
Integer value2 = entry2.get(0) == null : -1 ? entry2.get(0);
return value1.compareTo(value2);
}
});
In my case object was:
public class Edge {
private Integer weight;
public Edge(Integer weight) {
this.weight = weight;
}
public Integer getWeight() {
return weight;
}
}
And I call sort for (List edges = new ArrayList<>();) from other class:
Collections.sort(edges,(edge1,edge2) -> edge1.getWeight().compareTo(edge2.getWeight()));
Here is the result:
Exception img
Solution was to initialize value of object:
public class Edge {
private Integer weight = 0;
public Edge(Integer weight) {
this.weight = weight;
}
public Integer getWeight() {
return weight;
}
}
and it work!!!
code 0
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
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.
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).