I am using a SparseIntArray and I am puzzled by this behavior:
public static SparseIntArray getArray()
{
SparseIntArray result = new SparseIntArray();
result.append(0, 99);
result.append(1, 988);
result.append(2, 636);
return result;
}
public static void testArray()
{
SparseIntArray first = getArray();
SparseIntArray second = getArray();
if( first.equals(second) )
{
Log.v(TAG,"first "+first.toString()+" == second "+second.toString());
}
else
{
Log.v(TAG,"first "+first.toString()+" != second "+second.toString());
}
}
Output:
11-06 14:53:15.011: V/fileName(6709): first {0=99, 1=988, 2=636} != second {0=99, 1=988, 2=636}
I know that using == between two objects will compare the object addresses, which in this case are different, but here I am using SparseIntArray.equals(Object other) and the intended result is not unexpected.
I am sure I can roll my own compare method, but it sounds kind of silly. What is the point of having a base class Object.equals(Object other) method if we cant rely on it?
Can someone point to any mistake?
I just searched for the code of SparseIntArray. If you are referring to android.util.SparseIntArray, it doesn't override equals, which means it uses the default implementation of Object class, which compares the references.
What is the point for having a base class Object.equals(Object other) method if we cant rely on it?
Actually, you can't rely of the base class Object.equals, since it does precisely what you don't want to do:
public boolean equals(Object obj)
{
return (this == obj);
}
It's up to the writers of any class to decide whether to override equals and give a different implementation.
#Eran is right, Object.equals(Object) does not cut it.
I have made a simple static method to compare two instances
public static boolean compareSame( SparseIntArray first, SparseIntArray second )
{
// compare null
if( first == null )
{
return (second == null);
}
if( second == null )
{
return false;
}
// compare count
int count = first.size();
if( second.size() != count )
{
return false;
}
// for each pair
for( int index = 0; index < count; ++index )
{
// compare key
int key = first.keyAt(index);
if( key != second.keyAt(index))
{
return false;
}
// compare value
int value = first.valueAt(index);
if( second.valueAt(index) != value)
{
return false;
}
}
return true;
}
I will probably end up deriving my own version of SparseIntArray and override the equals method, I think this is more clean.
[EDIT] Here is the code for an sub-class implementing equals
import android.util.SparseIntArray;
public class SparseIntArrayComparable extends SparseIntArray {
#Override
public boolean equals( Object obj ) {
if( obj instanceof SparseIntArray ) {
SparseIntArray other = (SparseIntArray)obj;
// compare count
int count = size();
if( count != other.size() )
return false;
// for each pair
for( int index = 0; index < count; ++index ) {
if( keyAt(index) != other.keyAt(index))
return false;
if( valueAt(index) != other.valueAt(index) )
return false;
}
return true;
}
else
return false;
}
}
Related
I'm writing a method that returns a Set<String>. The set may contain 0, 1, or 2 objects. The string keys are also quite small (maximum 8 characters). The set is then used in a tight loop with many iterations calling contains().
For 0 objects, I would return Collections.emptySet().
For 1 object, I would return Collections.singleton().
For 2 objects (the maximum possible number), a HashSet seems overkill. Isn't there a better structure? Maybe a TreeSet is slightly better? Unfortunately, I'm still using Java 7 :-( so can't use modern things like Set.of().
An array of 2 strings would probably give the best performance, but that's not a Set. I want the code to be self-documenting, so I really want to return a Set as that is the logical interface required.
Just wrap an array with an AbstractSet. You only have to implement 2 methods, assuming you want an unmodifiable set:
class SSet extends AbstractSet<String> {
private final String[] strings;
SSet(String[] strings) {
this.strings = strings;
}
#Override
public Iterator<String> iterator() {
return Arrays.asList(strings).iterator();
}
#Override
public int size() {
return strings.length;
}
}
If you want, you can store the Arrays.asList(strings) in the field instead of a String[]. You can also provide 0, 1 and 2-arg constructors if you want to constrain the array only to be that length.
You can also override contains:
public boolean contains(Object obj) {
for (int i = 0; i < strings.length; ++i) {
if (Objects.equals(obj, strings[i])) return true;
}
return false;
}
If you don't want to create a list simply to create an iterator, you can trivially implement one as an inner class:
class ArrayIterator implements Iterator<String> {
int index;
public String next() {
// Check if index is in bounds, throw if not.
return strings[index++];
}
public boolean hasNext() {
return index < strings.length;
}
// implement remove() too, throws UnsupportedException().
}
The set is then used in a tight loop with many iterations calling contains().
I would probably streamline it for this. Perhaps something like:
public static class TwoSet<T> extends AbstractSet<T> {
T a = null;
T b = null;
#Override
public boolean contains(Object o) {
return o.equals(a) || o.equals(b);
}
#Override
public boolean add(T t) {
if(contains(t)){
return false;
}
if ( a == null ) {
a = t;
} else if ( b == null ) {
b = t;
} else {
throw new RuntimeException("Cannot have more than two items in this set.");
}
return true;
}
#Override
public boolean remove(Object o) {
if(o.equals(a)) {
a = null;
return true;
}
if(o.equals(b)) {
b = null;
return true;
}
return false;
}
#Override
public int size() {
return (a == null ? 0 : 1) + (b == null ? 0 : 1);
}
#Override
public Iterator<T> iterator() {
List<T> list;
if (a == null && b == null) {
list = Collections.emptyList();
} else {
if (a == null) {
list = Arrays.asList(b);
} else if (b == null) {
list = Arrays.asList(a);
} else {
list = Arrays.asList(a, b);
}
}
return list.iterator();
}
}
You can achieve this by
Make a class that implements Set interface
Override add and remove method
Add value upon class initialisation by super.add(E element)
Use that class instead
I have this class which consists in a group that can contain Circle and Triangle.
public class FiguresGroup {
private static final int NUM_FIGURES = 10;
private Figure[] figuresList = new Figure[NUM_FIGURES];
private int numF = 0;
public void add(Figure f) { figuresList[numF++] = f; }
public String toString() {
String s = "";
for (int i = 0; i < numF; i++) {
s += "\n" + figuresList[i];
}
return s;
}
private boolean found(Figure f) {
for (int i = 0; i < numF; i++) {
if (figuresList[i].equals(f)) return true;
}
return false;
}
private boolean included(FiguresGroup g) {
for (int i = 0; i < g.numF; i++) {
if (!found(g.figuresList[i])) return false;
}
return true;
}
private boolean equals(FiguresGroup g) {
if (g.included(this) && this.included(g)) return true;
}
I don't know how I can implement equals. I tried what you see here but it doesn't work.
For 2 groups to be equal one has to contain every element from the other and vice versa. How to make this work?
You missed a condition on numF of the two objects,
and the equals implementation has a compilation error.
Also note that the found method (depended upon by included) depends on correct implementation of Figure.equals.
If it's correctly implemented, then FiguresGroup.equals could be fixed this way:
private boolean equals(FiguresGroup g) {
return numF == g.numF && g.included(this) && this.included(g);
}
Also, FiguresGroup.equals doesn't override Object.equals, which is confusing. In fact, you're probably already confused by this. When you call figuresGroup.equals outside this class, the code compiles,
even though this method is private,
because actually Object.equals will be called instead of this private method.
You can fix that by overriding Object.equals:
#Override
public boolean equals(Object obj) {
if (!(obj instanceof FiguresGroup)) {
return false;
}
FiguresGroup other = (FiguresGroup) obj;
return numF == other.numF && other.included(this) && this.included(other);
}
In one of my Java classes I have these 2 very similar functions. Is there a way in Java to combine them into one function so I don't have to maintain 2 functions?
public static boolean areValuesValid( double [] values, int numElements ) {
if( values == null || values.length != numElements ) {
return false;
}
for( int i = 0; i < numElements; ++i ) {
if( Double.isNaN( values[i] ) ) {
return false;
}
}
return true;
}
public static boolean areValuesValid( float [] values, int numElements ) {
if( values == null || values.length != numElements ) {
return false;
}
for( int i = 0; i < numElements; ++i ) {
if( Float.isNaN( values[i] ) ) {
return false;
}
}
return true;
}
Your question is tricky in some ways for Java:
double and float are primitive types, and as such they are not part of a class hierarchy. The wrapper Double and Float classes extends Number, which extends Object, but
An array of primitive types is not the same as an array of objects, and Java does not autobox a float[] to Float[], for example.
There is no isNan(Number n) or isNan(Object o) method in the Java API, but the ones above that you used, that expect a double or a float. However, you can do Double.isNan(n.doubleValue()) for any Number n.
TL;DR In Java the common practice for primitive types is to have separate implementations for each one of them, like you did.
EDIT: As #azurefrog suggested:
public static boolean areValuesValid(Number[] values, int numElements) {
if (values == null || values.length != numElements) {
return false;
}
for (Number value : values) {
if (Double.isNaN(value.doubleValue())) {
return false;
}
}
return true;
}
And then you'd have to use Apache Commons ArrayUtils:
public static boolean areValuesValid(double[] values, int numElements) {
return areValuesValid(ArrayUtils.toObject(values), numElements);
}
public static boolean areValuesValid(float[] values, int numElements) {
return areValuesValid(ArrayUtils.toObject(values), numElements);
}
EDIT2: #shmosel's solution passes the array as an Object and from there avoids the conversion of the whole array to a boxed type. A solution worth considering to avoid that overhead.
It's not an ideal scenario, for the reasons #ericbn explained. But here's one way to avoid most of the duplication using a lambda:
public static boolean areValuesValid( double [] values, int numElements ) {
return areValuesValid(values, numElements, i -> !Double.isNaN(values[i]));
}
public static boolean areValuesValid( float[] values, int numElements ) {
return areValuesValid(values, numElements, i -> !Float.isNaN(values[i]));
}
private static boolean areValuesValid( Object values, int numElements, IntPredicate tester ) {
if( values == null || Array.getLength(values) != numElements ) {
return false;
}
for( int i = 0; i < numElements; ++i ) {
if( !tester.test(i) ) {
return false;
}
}
return true;
}
To simplify things, I would use instance of:
public static boolean areValuesValid( Object[] values ) {
if ( values == null ) {
return false;
}
for( int i = 0; i < values.length; ++i ) {
//if not Float and not Double return false
if ( values[i] instanceof Float || values[i] instanceof Double) {
return true;
}
}
return false;
}
I am not sure if you really must pass in the numElements.
EDIT: With your help I managed to fix my problem. I have edited my code to now show how I had to have it set up to get it working.
Currently I am having trouble coding a part which compares the content of two iterators. As part of the requirements for my assignment, I need to use a linkedlist to store the individual characters of the entered String. I have gotten to the point where I have two iterators which would contain the input one way and the reverse way.
String palindrom = input.getText();
String [] chara = palindrom.split (""); //this is successfully splitting them, tested.
int length = palindrom.length( ); // length == 8
System.out.println (length); //can use this for how many checks to do?
LinkedList ll = new LinkedList(Arrays.asList(chara));
Iterator iterator = ll.iterator();
Iterator desIterator = ll.descendingIterator();
/*while(iterator.hasNext() ){
System.out.println(iterator.next() );
}
while(desIterator.hasNext() ){
System.out.println(desIterator.next() );
}*/
boolean same = true;
while(iterator.hasNext()){
if(!iterator.next().equals(desIterator.next())){
same = false;
break;
}
}
And using the System.out I can see that they are being stored correctly, but I don't know how to check if the iterators store the same contents. What would be one of the simplest methods to compare the two iterators or convert them into something I can compare? To clarify I want to verify they contain the same elements in the same order.
boolean same = true;
while(iterator.hasNext()){
if(!desIterator.hasNext() || !iterator.next().equals(desIterator.next())){
same = false;
break;
}
}
System.out.println(same);
You need to iterate over both iterators simultaneously, i.e. with one loop. Here is a general comparison function (0 when equal, < 0 when A < B, > 0 when A > B):
static <T extends Comparable<S>, S> int compare(Iterator<T> a, Iterator<S> b) {
while (a.hasNext() && b.hasNext()) {
int comparison = a.next().compareTo(b.next());
if (comparison != 0) {
return comparison;
}
}
if (a.hasNext())
return 1;
if (b.hasNext())
return -1;
return 0;
}
To just check if they are equal, this can be simplified:
static <T, S> boolean equals(Iterator<T> a, Iterator<S> b) {
while (a.hasNext() && b.hasNext()) {
if (!a.next().equals(b.next())) {
return false;
}
}
if (a.hasNext() || b.hasNext()) {
// one of the iterators has more elements than the other
return false;
}
return true;
}
Guava implements this as Iterators.elementsEqual.
In both answers throw NullPointerException, if iterator.next() == null. This method is more optimal.
public static boolean equals(Iterator i1, Iterator i2) {
if (i1 == i2) {
return true;
}
while (i1.hasNext()) {
if (!i2.hasNext()) {
return false;
}
if (!Objects.equals(i1.next(), i2.next())) {
return false;
}
}
if (i2.hasNext()) {
return false;
}
return true;
}
I'm trying to use HashSet to store objects of a class that I created, but apparently the same objects seem to have two different hashes, which is why the contains method does not realize that the object is already in the HashSet. This leads to my program running out of heap memory.
I don't think I'm doing anything wrong, but I wanted a second opinion anyway. I've done similar operations before which all worked fine, which makes this particularly annoying. I'd appreciate any help.
Here's my code
move1 = new Move(t,s);
if(move1.hashCode()==new Move(t,s).hashCode())
System.out.println("match");
move2 = new Move(s,t);
moves.add(move1);
moves.add(move2);
if(moves.contains(new Move(t,s)))
System.out.println("match found");
Here's the Move class:
public class Move {
private int move1;
private int move2;
Move(int m1, int m2)
{
move1 = m1;
move2 = m2;
}
public String toString()
{
return String.valueOf(move1)+" "+String.valueOf(move2);
}
}
Here's the output I get
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.addEntry(HashMap.java:797)
at java.util.HashMap.put(HashMap.java:431)
at java.util.HashSet.add(HashSet.java:194)
at makeMove.<init>(makeMove.java:33)
You need to override the Object#hashCode() method in the Move class to let it return the same hashCode() value for the state of the Move instance. Don't forget to override Object#equals() as well.
See also:
Overriding equals and hashCode in Java
Hint: if you're using an IDE like Eclipse, you can also just autogenerate them. Rightclick somewhere the Move class, choose Source > Generate hashCode() and equals(). Here is how it look like then:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + move1;
result = prime * result + move2;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Move other = (Move) obj;
if (move1 != other.move1)
return false;
if (move2 != other.move2)
return false;
return true;
}
HashSet will determine equality based on calling hashCode() and equals(). You have not implemented these, so you'll inherite them from Object. The hashCode and equals methods of Object is just based on whether the references are equal.
That's why if(move1.hashCode()==new Move(t,s).hashCode()) is false. move1 is a different instance than the instance created by calling new Move(t,s).hashCode()
You'll need to implement hashCode and equals in your Move class.
e.g.(though perhaps non-optimal, and you might want a null safe equals - have your IDE generate them if it can)
public int hashCode() {
return move1 ^ move2 +;
}
public boolean equals(Object o) {
if(!other instanceof Move)
return false;
Move other = (Move)o;
return other.move1 == move1 && other.move2 == move2;
}
You have to override equals() and hashCode().
This may be an option.
import static java.lang.System.out;
public class Move {
private int move1;
private int move2;
Move(int m1, int m2) {
move1 = m1;
move2 = m2;
}
public String toString() {
return String.valueOf(move1)+" "+String.valueOf(move2);
}
public int hashCode() {
return move1 * 31 + move2 * 31;
}
public boolean equals( Object other ) {
if( this == other ) { return true; }
if( other instanceof Move ) {
Move m2 = ( Move ) other;
return this.move1 == m2.move1 && this.move2 == m2.move2;
}
return false;
}
public static void main( String [] args ) {
out.println( new Move(2,3).equals( new Move(2,3)));
out.println( new Move(1,1).hashCode() == new Move(1,1).hashCode() );
}
}
You have to define if the order of the move is relevant ( 1,2 isequals to 2,1 or not )
For more information:
What issues should be considered when overriding equals and hashCode in Java?