2.6 - Comparing Boolean Expressions
Two boolean expressions are equivalent if they always evaluate to the same result, no matter what inputs you give them. You can prove this using a truth table.
De Morgan’s Law gives you a way to rewrite boolean expressions:
// These two lines are logically equivalent: boolean result1 = !(a && b); boolean result2 = !a || !b;
Here’s the truth table that proves both laws. The paired columns match in every row, so the expressions are equivalent:
a | b | !(a && b) | !a || !b | !(a || b) | !a && !b |
true | true | false | false | false | false |
true | false | true | true | false | false |
false | true | true | true | false | false |
false | false | true | true | true | true |
In words: to move the
! inside, flip each part and swap && with ||. A common mistake is flipping the parts but keeping the same operator. !(a && b) is not the same as !a && !b: when a is true and b is false, the first is true and the second is false.When the parts are comparisons, negate each one by switching to the opposite operator. The opposite pairs are
< and >=, > and <=, and == and !=. Watch out: the opposite of x > 5 is x <= 5, not x < 5.int x = 12; boolean outside1 = !(x >= 1 && x <= 10); boolean outside2 = x < 1 || x > 10; // De Morgan's law: same value for every x System.out.println(outside1); // true System.out.println(outside2); // true
Comparing Objects
Two different variables can actually point to the exact same object. You can check this using
== and !=.Dog dog1 = new Dog("Rex"); Dog dog2 = dog1; // dog2 now points to the same object as dog1 System.out.println(dog1 == dog2); // true, same object
Since
dog1 and dog2 point to one object, a change made to that object through one variable shows up when you use the other. A new object, though, is always a separate object, even when its attributes match:Dog dog3 = new Dog("Rex"); System.out.println(dog1 == dog3); // false, two separate objects System.out.println(dog1 != dog3); // true
You can also compare a reference against
null to check whether it’s actually pointing to an object at all.Dog myDog = null; System.out.println(myDog == null); // true
This matters because calling a method on a
null reference throws a NullPointerException. Check for null first, and short-circuit evaluation (2.5) keeps the method call from running:String name = null; if (name != null && name.length() > 3) { System.out.println("Long name"); } // no error: name != null is false, so name.length() never runs
Classes often define their own
.equals() method, which lets you specify what actually counts as “equal” for two objects of that class, usually based on comparing their attributes rather than their memory address. Note: actually writing your own .equals() method is outside the scope of this course, you just need to know how to use one that’s already provided.String is one of these classes. Its equals method checks whether two strings have the same characters in the same order. So for objects, == asks “same object?” while equals asks “same content?”String s1 = new String("cat"); String s2 = new String("cat"); String s3 = s1; System.out.println(s1 == s2); // false, two different objects System.out.println(s1.equals(s2)); // true, same characters System.out.println(s1 == s3); // true, same object System.out.println(s1.equals(s3)); // true
Each class decides what counts as equal. For example, a class for points on a graph might say two points are equal when their x and y values match. If a class doesn’t define its own
equals, it uses the version every class gets from Object, which works just like ==.