## IntelliJ IDEA

IntelliJ IDEA – the Leading Java and Kotlin IDE, by JetBrains

Tips & Tricks

# The Inspection Connection – Issue #2, Proposition Transformation

Boolean algebra can be difficult to reason about, which is why IntelliJ IDEA provides several inspections and intentions to simplify boolean expressions, improve readability and help make your code less prone to bugs. Here are just a few you may encounter while writing Java.

### 1. De Morgan’s Laws

De Morgan’s laws are (1) ¬a ∧ ¬b ≡ ¬(a ∨ b) and (2) ¬a ∨ ¬b ≡ ¬(a ∧ b). We can use these laws to transform boolean expressions programmatically, saving you the hassle of drawing a truth table to confirm your own good intuition.

```public void deMorgans(boolean p, boolean q, boolean r) {
if (!p && !q && !r) {
System.out.println("p and q and r are *all* false");
} else {
System.out.println("at least one of p, q or r is true");
}
}```

By placing your cursor on line 2, then pressing Alt+Enter,w to select Replace ‘&&’ with ‘||’, IntelliJ IDEA will apply De Morgan’s first law, by first replacing conjunctions with disjunctions and negating the whole clause, leaving us:

```public void deMorgans(boolean p, boolean q, boolean r) {
if (!(p || q || r)) {
System.out.println("p and q and r are *all* false");
} else {
System.out.println("at least one of p or q or r is true");
}
}```

As you can see, this may not always be the shortest or most natural form, so we can easily swap back and forth by between them by pressing Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z, or by repeating the inspection to apply De Morgan’s first law in reverse.

### 2. Rearranging control flow

IntelliJ IDEA provides two intentions for merging nested Ifs with conjunction and equivalent Ifs with disjunction, and two for separating them, via Split if and Extract if condition, respectively. For example, consider the following scenario:

```if (a) {
if (b) {
x = 1;
}
}```

By applying the first intention Merge nested ‘if’s, this can be reduced to:

```if (a && b) {
x = 1;
}```

Likewise, sequential ‘if’ conditions with identical bodies can be joined with disjunction.

```if (a) {
x = 1;
}
if (b) {
x = 1;
}```

By placing your cursor over the ‘i’ or ‘f’ on line #1 and applying the intention Merge sequential ‘if’s, this can be reduced to:

```if (a || b) {
x = 1;
}```

Now, if you want to break up a complex ‘if’ statement, you can place the cursor over a boolean expression, and apply the intention Extract if (…), where ‘…’ indicates the expression to be extracted.

```if (a || b && c) {
x = 1;
} else {
x = 2;
}```

Whichever disjunct your cursor is covering when the inspection is applied, that condition will be extracted into a new If statement and either nested inside the existing one or placed directly afterwards.

```if (b && c) {
x = 1;
} else if (a) {
x = 1;
} else {
x = 2;
}```

Keep in mind, if that if the condition contains a function call, this refactoring may alter the sequential structure of your program.

### 3. Flip Comparison

By reversing the traditional order of conditionals, Yoda notation claims two benefits: reducing null pointer errors and preventing accidental assignment. Many programmers follow this style in order to call attention to the boundary value:

```public boolean isAcademic(String email) {
if ("".equals(email)) {
return false;
} else if (6 > email.length()) {
return false;
}
return email.contains(".edu");
}```

However we can see that Yoda notation hides a null pointer that may potentially reappear later (in this case on line #4). The second motivation, that Yoda notation prevents ‘=’ where ‘==’ is intended, is demonstrated below.

```public boolean shortCircuitAnd(Boolean a, Boolean b) {
if(a = false) { //a = false -> no error
return false;
}
if(false = b) { //false = b -> compiler error
return false;
}

return true;
}```

In Java, there are very few cases where accidental assignment is also syntactically valid, and IntelliJ IDEA will detect those cases where assignments are used inside a condition. So we can safely swap Yoda conditions with the more traditional variation.

```public boolean isAcademic(String email) {
if (email == null) {
return false;
} else if (email.equals("")) {
return false;
} else if (email.length() < 6) {
return false;
}

return email.contains(".edu");
}```

No matter which convention your code adopts, is important to use one consistently across your project. IntelliJ IDEA supports annotations for nullity inference, so the rationale behind Yoda notation in Java is less clear, but the choice is yours.

### 4. Avoiding negative conditionals

In Clean Code, Robert Martin writes, “Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives.” (Martin, [G29]). IntelliJ IDEA has three inspections to help you stay positive.

```public boolean isAcademic(String email) {
if (email != null && !email.isEmpty()) {
return email.contains(".edu");
}

return false;
}```

When conditionals are negative, this is a good indication that control flow can be refactored. When refactoring your code, you should apply the intention Invert If Condition. Notice how De Morgan’s law is implicitly used to refactor this clause.

```public boolean isAcademic(String email) {
if (email == null || email.isEmpty()) {
return false;
}

return email.contains(".edu");
}```

IntelliJ IDEA can detect when a boolean method is always inverted, giving you the opportunity to rename these functions. In order to trigger a global inspection like this one, you will need to explicitly run it. You can find this inspection under Analyze|Inspect Code.

```class Applicant {
if (email == null || email.isEmpty()) {
return true;
}

return !email.contains(".edu");
}

void updateEmail(String email) {
this.email = email;