I need to compare two Objects. If there is a difference I need to log it corresponding to particular difference and return the true.
For example:
private boolean compTwoObjects(Object objA, Object ObjB) {
if(objA.getType() != objB.getType()) {
logTheDifference("getType is differing");
return true;
}
.
.
.
// Now this could invoke other composite methods
if(checkFont(objA.getFont(), objB.getFont()) {
logTheDifference("Font is differing");
return true;
}
}
private boolean checkFont(Font fontObjA, Font fontObjB) {
if(fontObjA.getBold() != fontObjB.getBold()) {
logTheDifference("font bold formatting differs");
return true;
}
.
.
.
if(fontObjA.getAllCaps() != fontObjB.getAllCaps()) {
logTheDifference("font all caps formatting differs");
return true;
}
.
.
.
if(checkBorderDiff(fontObjA.getBorder(), fontObjB.getBorder())) {
logTheDifference("border diff");
return true;
}
}
private boolean checkBorderDiff(Border borderObjA, Border borderObjB) {
if (borderObjA.getColor() != null || borderObjB.getColor() != null) {
if (!borderObjA.getColor().equals(borderObjB.getColor())) {
logIt("border color differing");
return true;
}
}
if (borderObjA.getDistanceFromText() != borderObjB.getDistanceFromText()) {
logIt("distance of the border from text or from the page edge in points differing");
return true;
}
if (borderObjA.isVisible() != borderObjB.isVisible()) {
logIt("border visibility differing");
return true;
}
if (borderObjA.getLineStyle() != borderObjB.getLineStyle()) {
logIt("line style differing for border");
return true;
}
if (borderObjA.getLineWidth() != borderObjB.getLineWidth()) {
logIt("border width in points differing");
return true;
}
if (borderObjA.getShadow() != borderObjB.getShadow()) {
logIt("border shadow differing");
return true;
}
}
//And it is going like this.
My problem is I want to avoid multiple if statements in the methods. Also I want to log the messages corresponding to particular difference.
I have read few similar type of problems on stackoverflow solved either by command pattern or HashMap. But they don't include comparisons in that.
I want to refactor my code to get rid of series of if's.
Have a system of comparators, backed by generics. Every comparer will also know what is next in line. For example:
interface IComparer<T> {
boolean areDifferent (T first, T second);
}
class FontComparer implements IComparer<Font> {
#Override
public boolean areDifferent(Font first, Font second) {
// Compare fonts start
// ..
// Compare fonts end
return new BorderComparer().areDifferent(first.getBorder(), second.getBorder());
}
}
class BorderComparer implements IComparer<Border> {
#Override
public boolean areDifferent(Border first, Border second) {
//Do border comparison alone
return false;
}
}
You could setup a comparer chain now, and bail out when comparison fails. Otherwise, comparison goes to the comparer next in the chain.
The client code will finally look like:
Object one = new Object();
Object two = new Object();
new ObjectComparer().areDifferent(one, two);
Have you considered enums?
private enum FontCmp {
Bold {
#Override
boolean cmp(Font a, Font b) {
return a.getBold() != b.getBold();
}
},
AllCaps {
#Override
boolean cmp(Font a, Font b) {
return a.getAllCaps() != b.getAllCaps();
}
},
Border {
#Override
boolean cmp(Font a, Font b) {
return BorderCmp.compare(a.getBorder(), b.getBorder());
}
};
// Each enum has one of these.
abstract boolean cmp(Font a, Font b);
// Compare them all and log any failures.
static boolean compare(Font a, Font b) {
for (FontCmp c : FontCmp.values()) {
if (c.cmp(a, b)) {
logIt("FontCmp-" + c + " failed");
return false;
}
}
return true;
}
}
You could also use reflection as described here. Also look into introspection as described here
Fundamentally you are trying to do a series of comparisons, so there is little choice but to do a series of comparisons.
What you could do is define an interface/enum/abstract class which is a FieldChecker. That FieldChecker would have an abstract method implemented differently in each FieldChecker:
String performCheck(Font a, Font b) {
if (DO CHECK HERE) {
return "failure message";
}
return null;
}
Then your check function just becomes:
for (FieldChecker fc: fieldCheckers) {
String res = fc.performCheck(a,b);
if (res != null) {
return res;
}
}
return "All ok";
Related
I am trying to find a way to reduce the length and simplify the following repetitive methods :
boolean circleFlag, squareFlag, diamondFlag;
public void shapeButtonPressed(String shapeType) {
if (shapeType.equals("Circle")) {
circlePressed();
} else if (shapeType.equals("Square")) {
squarePressed();
} else if (shapeType.equals("Diamond")) {
diamondPressed();
}
}
public void circlePressed() {
if(!circleFlag){
//set only circleFlag true and the rest false.
circleFlag = true;
squareFlag = false;
diamondFlag = false;
//(... some code)
} else {
//set all flags false.
circleFlag = false;
diamondFlag = false
squareFlag = false;
//(... some different code)
}
}
public void squarePressed() {
if(!squareFlag){
//set only squareFlag true and the rest false.
squareFlag = true;
circleFlag = false;
diamondFlag = false;
//(... some code)
} else {
//set all flags false.
circleFlag = false;
diamondFlag = false
squareFlag = false;
//(... some different code)
}
}
public void diamondPressed() {
if(!diamondFlag){
//set only diamondFlag true and the rest false.
diamondFlag = true;
squareFlag = false;
circleFlag = false;
//(... some code)
} else {
//set all flags false.
circleFlag = false;
diamondFlag = false
squareFlag = false;
//(... some different code)
}
}
Things I have tried
I have tried to set all my values to Boolean type, set them in a ArrayList<Boolean> and change the shapePressed(String shapeType) method to
public void shapePressed(String shapeType) {
Boolean currFlag = false;
if (shapeType.equals("Circle")) {
currFlag = circleFlag;
} else if (shapeType.equals("Square")) {
currFlag = squareFlag;
} else if (shapeType.equals("Diamond")) {
currFlag = diamondFlag;
}
if (!currFlag){
for (Boolean flag : shapeFlag) flag = ( flag == currFlag ) ? true : false;
//(...)
} else {
for (Boolean flag : shapeFlag) flag = false;
//(...)
}
}
but the line ( flag == currFlag ) compares the booleans as values and not as individual objects. So my currFlag is pointless in this above method.
I then though of using a HashMap<String ,Boolean> but whenever I compare the values given a key (String shapeType from the method parameter), I encounter the same problem as above.
What is a way to simplify this code ?
When a given shape is activated, you just invert that flag. Then the other flags get set to false.
So, trivially, you could simplify your circlePressed() logic to:
public void circlePressed() {
circleFlag = !circleFlag;
squareFlag = false;
diamondFlag = false;
}
Of course there's still a lot of repetition. You could refactor this further to an enum and track the state there.
public enum Flag {
CIRCLE( false ),
SQUARE( false ),
DIAMOND( false ); // default state is false for all
private boolean state;
private Flag(boolean state) {
this.state = state;
}
public void flipState() {
this.state = !this.state;
}
public void setState(boolean state) {
this.state = state;
}
}
// notice this method takes the Flag not a string
public void shapeButtonPressed(Flag selected) {
// iterate through all the flags ...
for( Flag flag : Flag.values() ) {
if (flag == selected) {
// invert the "pressed" flag state
flag.flipState();
} else {
// ... and set the rest to false
flag.setState(false);
}
}
}
The built-in values method on enums returns a list of all of the defined enums, so we can just iterate across them.
It's a bit gimmicky, I admit, since it's not really what enums are intended for, but it simplifies your logic quite a bit.
You could use an enum.
public enum Shape {
CIRCLE, SQUARE, DIAMOND
}
Then, use that in your code like so;
Shape shape;
public void shapeButtonPressed(Shape selectedShape) {
shape = selectedShape;
}
If you can't change the method signature of shapeButtonPressed and it has to take a String, you can stil do
Shape shape;
public void shapeButtonPressed(String shapeType) {
if (shapeType.equals("Circle")) {
shape = Shape.CIRCLE;
} else if (shapeType.equals("Square")) {
shape = Shape.SQUARE;
} else if (shapeType.equals("Diamond")) {
shape = Shape.DIAMOND;
}
}
As an alternative to my approach with enums above (that I highly recommend over this one), you can do a more "C-style" solution using a bitmask instead of boolean flags.
A bitmask is essentially a numeric (or binary for that matter) value of which each bit represents a boolean value.
int shapeFlags;
public void shapeButtonPressed(String shapeType) {
if (shapeType.equals("Circle")) {
shapeFlags = 1;
} else if (shapeType.equals("Square")) {
shapeFlags = 2;
} else if (shapeType.equals("Diamond")) {
shapeFlags = 4;
}
}
This still leaves you the option to set more than one shape to true while being able to override all flags in a single operation.
Mappings from numeric values to shapes would look like this:
0 : no shape
1 : circle
2 : square
3 : circle & square
4 : diamond
5 : diamond & circle
6 : diamond & square
7 : all three
I'm trying to make a generic tuple class. It stores its elements as an ArrayList. Of course, this class should override hashcode and equals methods.
How could I make hashcode method for this class? You see, in the code, I am having trouble.
Also, for the equals method, why does the compiler force me to use the '?'. Why couldn't I just use the T?
public static class Tuple<T> {
ArrayList<T> tuple = new ArrayList<>();
public Tuple(ArrayList<T> items) {
for (T item : items) {
tuple.add(item);
}
}
#Override
public int hashCode() {
T sum = ???;
for (T item : tuple) {
sum += item.hashCode();
}
return sum;
}
#Override
public boolean equals(Object o) {
if (o instanceof Tuple<?>) {
Tuple<?> tup= (Tuple<?>) o;
if (tup.tuple.size() != this.tuple.size()) {
return false;
}
for (int i = 0; i < this.tuple.size(); i++) {
if (this.tuple.get(i) != tup.tuple.get(i)) {
return false;
}
}
return true;
} else {
return false;
}
}
}
As mentioned in the comments, we should delegate the hashCode and the equals methods to the ArrayList<T> tuple instance variable. For the hashCode it's trivial. For the equals it's just a little more complicated than that because we don't want our custom Tuple to be equals with an ArrayList. So here it is:
public class Tuple<T> {
// I made this private because I'm pedantric ;)
private final ArrayList<T> tuple = new ArrayList<>();
// this does the same as your code, it's just easier to read
public Tuple(ArrayList<T> items) {
tuple.addAll(items);
}
#Override
public int hashCode() {
return tuple.hashCode();
}
// generated by eclipse
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tuple other = (Tuple) obj;
if (tuple == null) {
if (other.tuple != null)
return false;
} else if (!tuple.equals(other.tuple))
return false;
return true;
}
}
If you want to deal with the case when the tuple can be null, then you can use a slightly more complex hashCode:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tuple == null) ? 0 : tuple.hashCode());
return tuple.hashCode();
}
In general, I don't like to write these methods myself. Usually, I make my IDE to generate the stuff. All I need to take care of is to re-generate it when I add new fields. Apache HashCodeBuilder and EqualsBuilder are also great alternatives.
I have the problem, that my equals method doesnt work as i want it to. I want to implement a deterministic turing machine, so I want to add the method findCommand(), which searchs through a arraylist of commands. So I decided to create a searchDummy to find all Transitions that are available for the Configuration I have.
Class States:
public class States {
private int stateId;
private boolean rejState;
private boolean accState;
private boolean stopState;
private List<Commands> commands = new ArrayList<Commands>();
equals in class States:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof States) {
States otherState = (States) other;
return (stateId == otherState.stateId);
} else {
return false;
}
}
hashCode:
#Override public int hashCode() {
StringBuilder b = new StringBuilder(stateId);
return b.toString().hashCode();
}
this is the findCommand method in States:
public Commands findCommand(States state, char inputTapeChar,
char[] tapeChars) {
Commands searchDummy = new Commands(state, inputTapeChar, tapeChars,
null, null, null, null);
int pos = commands.indexOf(searchDummy);
return pos >= 0 ? commands.get(pos) : null;
}
commands is my arraylist, so I want to find the searchDummy with indexOf().
I have the class Commands, which holds the attribute Configuration configuration, the class Configuration, which holds the attributes of a Configuration and the attribute Transition transition and the class transition that holds the attributes for itself.
Class Commands:
public class Commands implements Comparable<Commands> {
private Configuration configuration;
Class Configuration:
public class Configuration {
private Transition transition;
private States state;
private char inputTapeChar;
private char[] tapeChars;
Class Transition:
public class Transition {
private States targetState;
private Direction inputTapeHeadMove;
private char[] newTapeChars;
private Direction[] tapeHeadMoves;
i have this equals method in Commands:
#Override public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof Commands) {
Commands otherCmd = (Commands) other;
return (configuration.equals(otherCmd.configuration));
} else {
return false;
}
}
and this hashcode
#Override
public int hashCode() {
StringBuilder b = new StringBuilder(configuration.getState() + ","
+ configuration.getInputTapeChar());
for (char c : configuration.getTapeChars()) {
b.append("," + c);
}
return b.toString().hashCode();
}
then almost the same in Configuration:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof Configuration) {
Configuration otherConfi = (Configuration) other;
return (state.equals(otherConfi.state))
&& (inputTapeChar == otherConfi.inputTapeChar)
&& (Arrays.equals(tapeChars, otherConfi.tapeChars));
} else {
return false;
}
}
hashcode:
#Override
public int hashCode() {
StringBuilder b = new StringBuilder(state + "," + inputTapeChar);
for (char c : tapeChars) {
b.append("," + c);
}
return b.toString().hashCode();
}
equales in class State:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof States) {
States otherState = (States) other;
return (stateId == otherState.stateId);
} else {
return false;
}
}
so my question:
when I debug this it goes through until it's finished with the checks but when it should return the value it stucks at Configuration.equals(...) and shows the error no source found!
what is the problem? Are the hashcodes wrong? Or are the equals wrong?
I never used equals before so I dont know when i need to use it or how i need to fix this. thanks for your help.
Your hashCode implementation looks suspect - all that String stuff is not standard.
For example for your Transition class should be something like this:
#Override
public int hashCode() {
int result = 17;
result = 31 * result + targetState.hashCode();
result = 31 * result + inputTapeHeadMove.hashCode();
result = 31 * result + newTapeChars.hashCode();
result = 31 * tapeHeadMoves.hashCode();
return result;
}
Most IDEs will offer autogen of hashCode and equals methods.
I have list of objects:
List<City> cities = city.getList();
I would like to remove duplicates (where duplicates mean objects with the same value of parameter name and different (id, and other parameters);
I have code for that:
for(City c: cities) {
System.out.println("analise " + c.name);
if(!temp.contains(c)) {
temp.add(c);
}
}
I've wrote for that hashCode() and equals() method:
#Override
public int hashCode() {
return id.hashCode();
}
...
#Override
public boolean equals(Object other) {
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof GenericDictionary))return false;
GenericDictionary otherMyClass = (GenericDictionary) other;
if(this.name == otherMyClass.name) {
return true;
} else {
return false;
}
}
But it dosnt apply it. It use object.equals() method instead of mine
It looks like your problem is in String comparison :
if(this.name == otherMyClass.name)
Change it to :
if(this.name.equals(otherMyClass.name))
i have some problems with some of my methods for my MultiSet class.
This is a tester, and MultiSet class should get the output: "Succes!" if it works correctly.
This is the tester:
public class MultiSetTest {
public static void main(String[] args) {
MultiSet<String> a = new MultiSet<String>();
MultiSet<String> b = new MultiSet<String>();
a.add("Foo");
a.add("Bar");
a.add("Foo");
System.out.println("a:" + a); // test toString
b.add("Bar");
b.add("Foo");
b.add("Bar");
b.add("Foo");
System.out.println("b:" + b);
assert !a.equals(b) : "Failed test 1!"; // test equals
assert b.remove("Bar") : "Failed test 2!"; // test remove
assert a.equals(b) : "Failed test 3!";
for(String s : a) { // test iterator
assert b.remove(s) : "Failed test 4!";
}
assert b.size() == 0 : "Failed test 5!";
Set<String> baseSet = new HashSet<String>(a);
assert baseSet.size()==2 : "Failed test 6!";
b = new MultiSet<String>(a);
assert a.equals(b) : "Failed test 7!";
try {
assert false;
System.out.println("Please enable assertions!");
}
catch(AssertionError e) {
System.out.println("Success!");
}
}
}
And my Multiset class:
public class MultiSet<E> extends AbstractCollection<E>
{
private int size = 0;
private Map<E, Integer> values = new HashMap<E, Integer>();
public MultiSet()
{
}
public MultiSet(Collection<E> c)
{
addAll(c);
}
public boolean add()
{
return false;
}
public boolean remove()
{
return false;
}
public Iterator<E> iterator()
{
return new Iterator<E>()
{
private Iterator<E> iterator = values.keySet().iterator();
private int remaining = 0;
private E current = null;
public boolean hasNext()
{
return remaining > 0 || iterator.hasNext();
}
public E next()
{
if (remaining == 0)
{
current = iterator.next();
remaining = values.get(current);
}
remaining--;
return current;
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public boolean equals(Object object)
{
if (this == object) return true;
if (this == null) return false;
if (this.getClass() != object.getClass()) return false;
MultiSet<E> o = (MultiSet<E>) object;
return o.values.equals(values);
}
public int hashCode()
{
return values.hashCode()*163 + new Integer(size).hashCode()*389;
}
public String toString()
{
String res = "";
for (E e : values.keySet());
//res = ???;
return getClass().getName() + res;
}
public int size()
{
return size;
}
}
Maybe if you could help me on the way with either add or remove, then i can probably work the other one out.
Also, my equals doesn't appear to work correctly,
and I'm unsure about how to work out "res" at String toString. Don't mind my return statement, i'll throw in some brackets etc. later to make it look good.
Thank you for your help.
// Chris
Why not on of use well-tested Google Guavas's Multisets instead of reinventing the wheel? You can choose one of many implementations:
ConcurrentHashMultiset,
EnumMultiset,
ForwardingMultiset,
HashMultiset,
ImmutableMultiset,
LinkedHashMultiset,
TreeMultiset
what should cover your use case or - if you really want - implement Multiset interface by yourself, looking into sources of default implemntations.
EDIT:
Your implementation breaks Collecion interface contract - you cannot return false for add(E e). Read Collection docs:
boolean add(E e)
Parameters:
e - element whose presence in this collection is to be ensured
Returns:
true if this collection changed as a result of the call
Throws:
UnsupportedOperationException - if the add operation is not supported by this collection
If you want to use read-only Multiset use either ImmutableMultiset (more specifically ImmutableMultiset.copyOf(Iterable)) or implement Multiset
's interface add(E e) method throwing UnsupportedOperationException.