Minifying Or/And expressions in Java? - java

I've always been curious if it's possible to simplify an Or expression Java. Example:
int mapVal = occurrenceMap.get(node.nextNode.nodeVal);
if (mapVal != null || mapVal != 5 )
versus...
if (occurrenceMap.get(node.nextNode.nodeVal) != ( null || 1) )
IMO, the second is more readable, but wondering if the language supports something like this.

Use getOrDefault
occurrenceMap.getOrDefault(node.nextNode.nodeVal, 5) != 5

if (occurrenceMap.get(node.nextNode.nodeVal) != ( null || 1) )
the second is more readable, but wondering if the language supports
something like this.
No Java not support that.
For a good solution I would like to use :
Integer i = occurrenceMap.get(node.nextNode.nodeVal);
if (i != null || i != 1)
Note : as Tim Biegeleisen mention in comment primitive int or type in general can't be null in Java.

First, int cannot be null. You don't need to check against null if you have an int. It just cannot happen.
Here is a method that checks whether a value is equal to any of a list of values:
public static <T> boolean anyEquals(T value, T... values) {
for (T val: values) {
if (val == value) { // or val.equals(value)
return true;
}
}
return false;
// implementation with streams
// return Arrays.stream(values).anyMatch(x -> x == value); // or x.equals(value)
}
Usage (supposing you are using Integers instead of int):
Integer i = ...;
boolean b = anyEquals(i, 5, 10, 15);

If you're into simplifying boolean expressions you should learn about some axioms and laws:
!!a = a
(!a || a) = true
(!a && a) = false
(true && a) = a
(false && a) = false
(true || a) = true
(false || a) = a
(!a || !b) = !(a && b)
(!a && !b) = !(a || b)
(a != b) = !(a == b)
(a <= b) = (b > a)
(a >= b) = (b < a)
The second one you've mentioned can't possibly be used in
Java because (a || b) already has a meaning so a == (c || d) already has a fixed meaning and changing this would probably break a lot of code. There might be languages that support such notations but they'll use a different operator instead of the binary boolean operator because otherwise it'd be impossible to distinguish what the programmer actually wants.
You could absolutely add such a feature to Java but you'd have to create a new operator to do this. But as of now: Java doesn't have this, and most languages don't.
Some languages allow you to do things like "a < b < c" which not all languages support (you'll have to write "a < b AND b < c").
You technically can create helper functions for this such as
"if isOneOf(mapVal, a, b)" but probably this is not going to be used widespread (most importantly because it'd require some runtime trickery to do this).

Related

Is there a limit to how long an if statement can be in Java?

I was working on a game called the L game. In the function to check for a win, I had an if statement like this:
if (buttons[i][0].getText().equals(colour) || buttons[i][0].getText().equals("0") && buttons[i][1].getText().equals(colour) || buttons[i][1].getText().equals("0") && buttons[i][2].getText().equals(colour) || buttons[i][2].getText().equals("0") && buttons[i+1][2].getText().equals(colour) || buttons[i+1][2].getText().equals("0") && !(buttons[i][0].getText().equals(colour) && buttons[i][1].getText().equals(colour) && buttons[i][2].getText().equals(colour) && buttons[i+1][2].getText().equals(colour))) {
return false;
}
And this code didn't work. Not that I was getting an error, just it was not doing what it was supposed to do when a player won. However changed it to a few if statements in each other like this:
if (buttons[i][0].getText().equals(colour) || buttons[i][0].getText().equals("0")) {
if (buttons[i][1].getText().equals(colour) || buttons[i][1].getText().equals("0")) {
if (buttons[i][2].getText().equals(colour) || buttons[i][2].getText().equals("0")) {
if (buttons[i+1][2].getText().equals(colour) || buttons[i+1][2].getText().equals("0")) {
if (!(buttons[i][0].getText().equals(colour) && buttons[i][1].getText().equals(colour) && buttons[i][2].getText().equals(colour) && buttons[i+1][2].getText().equals(
return false;
}
}
}
}
}
And this does work.
Your two code snippets behave differently not because you have exceeded some "maximum characters in an if statement" limit, but because && has a higher precedence than ||.
When you say:
A || B && C || D
You meant
(A || B) && (C || D)
But without any parentheses, Java thought you meant:
A || (B && C) || D
This is because && has a higher precedence than ||. It's kind of like how you do multiplication first, than addition.
That aside, there is theoretically no limit on how long an if condition can be. It is not specified in the Java Language Specification. As long as you have enough RAM for the compiler, disk space to store the source file, and time for the compilation process, your code should compile eventually, if we assume the compiler implements the spec perfectly.
This doesn't mean that you should be writing super long if statements, though. Code is not only read by computers. Arguably, it is more often read by people than computers. So please keep that in mind when writing code.
A first step to refactoring your code would be to write a method like this:
private bool isButton0(int x, int y) {
return buttons[x][y].getText().equals("0");
}
so that you don't have to repeatedly say buttons[i][1].getText().equals("0").

How to fix sonar issues for Reduce the number of conditional operators (5) used in the expression (maximum allowed 3) in java

ObjectTest systemError = (ObjectTest ) o;
//New Code
result &= Objects.equals(this.exp1, systemError.exp1);
result &= Objects.equals(this.exp2, systemError.exp2) ;
result &= Objects.equals(this.exp3, systemError.exp3);
result &= Objects.equals(this.exp4, systemError.exp4);
result &= Objects.equals(this.exp5, systemError.exp5) ;
result &= Objects.equals(this.exp6, systemError.exp6);
return result;
//Old Code
return Objects.equals(this.exp, systemError.exp) &&
Objects.equals(this.exp1, systemError.exp1) &&
Objects.equals(this.exp2, systemError.exp2) &&
Objects.equals(this.exp3, systemError.exp3) &&
Objects.equals(this.exp4, systemError.exp4) &&
Objects.equals(this.exp5, systemError.exp5) &&
Objects.equals(this.exp6, systemError.exp6);
Does the New code is the solution for Old code ?Can any one shed some confirmation on this.
Note that a &= b is same as a = a & b which will have the same result as a = a && b for practical purposes (except for performance as irrespective of the value of a, b will also be evaluated in case of a & b while in case of a && b, b is not processed if a is false)
On this basis, your new code can be indeed the solution for the old code provided you start your new code with result = Objects.equals(this.exp, systemError.exp); and end it with return result;
Feel free to let me know if you still have any problem understanding it and I will try to elaborate my explanation a bit further.

Java 8 Complex Stream filters And vs Or

I have a table object that has three columns that I am using to filter events.
The three columns with hypothetical values:
Component Event SubEvent
A B C
A B D
I am trying to create an event stream that filters out the first row but not the second. I've tried this a couple different ways with mixed results.
return events -> save(events.stream().filter(event ->
A != event.getComponent() &&
B != event.getEventType() &&
C != event.getEventSubType())
.collect(Collectors.toList())
This behaves like an "or" and filters out both rows.
i.e. if component == A || event == B || subEvent == C
What I really want is
IF (component == A && event == B && subEvent == C) then filter out but keep
everything else.
I've modified my filter to
.filter(event -> C != event.getEventSubType())
But then I risk missing other events where subEvent == C but the Component and Event value do not match A and B.
Appreciate any other strategy suggestions on best practices to set up this kind of compound filter. Thanks!
Note that skip(1) allows to skip the first element of the Stream.
About your issue, your actual filter :
filter(event ->
A != event.getComponent() &&
B != event.getEventType() &&
C != event.getEventSubType())
means that are kept in the stream only elements that respect these three conditions.
Look at these rows :
Component Event SubEvent
A B C
A B D
The condition is false for the first line. So the element is not kept.
But the condition is also false for the second line as a series of logical AND is true only if all conditions are true and two of them are not true :
A != event.getComponent() --> false
B != event.getEventType() --> false
C != event.getEventSubType() --> true
So no one of these line are kept.
What you should write is :
filter(event ->
!(A == event.getComponent() &&
B == event.getEventType() &&
C == event.getEventSubType()))
So why not create filter that exactly matches first, row and then negate it in your stream filter? That way you will reject all events that match first row, like so:
Predicate<Event> FIRST_ROW = event->
Object.equals(A , event.getComponent()) &&
Object.equals(B , event.getEventType() &&
Object.equals(C , event.getEventSubType();
save(events.stream()
.filter(FIRST_ROW.negate())
.collect(Collectors.toList())
Try as
save(events.stream().filter(event ->
!("A".equals(event.getComponent()) &&
"B".equals(event.getEventType()) &&
"C".equals(event.getEventSubType()))
.collect(Collectors.toList())
Or equivalently
save(events.stream().filter(event ->
!"A".equals(event.getComponent()) ||
!"B".equals(event.getEventType()) ||
!"C".equals(event.getEventSubType())
.collect(Collectors.toList())

Idiomatic way to ensure many values are equal

Say I have a list of many primitive variables:
final int a = 3;
final int b = 4;
final int c = 4;
final int d = 4;
final int e = 4;
What's an idiomatic way to make sure they all hold the same value? The obvious way is simply
if (a == b && a == c && a == d && a == e) // ...
But I think this is error prone and hard to read, especially when the variables have proper names, unlike my example.
if ( numCategories == numTypes && numCategories == numColours
&& numCategories == numStyles && numCategories == numPrices) // ...
It would be nice if we could do the comparison like this:
if (a == b == c == d == e)
but obviously a == b resolves to a boolean so we can't compare that to c.
Is there a library function in the JDK or another utility library with maybe a signature somewhat like this?
static boolean areEqual(int... numbers)
then we could use it like so:
if (areEqual(a, b, c, d, e)) //...
I could easily write a function like this myself, but why reinvent the wheel if you don't have to?
Maybe there's another idiomatic way to accomplish this that I'm missing.
Using Streams, you can take advantage of some convenient methods to achieve your goal.
You can use Stream's or IntStream's distinct() combined with count() to find the number of unique elements:
For int variables:
if (IntStream.of(a,b,c,d,e).distinct().count() == 1) {
}
For reference type variables:
if (Stream.of(a,b,c,d,e).distinct().count() == 1) {
}
Another way, which is probably less efficient (but I'll keep it here since it's the first thing I thought about) is creating a Stream of all the elements you want to compare and then collecting them into a Set and checking the size of the Set is 1 (since Set doesn't allow duplicates) :
if (IntStream.of(a,b,c,d,e).boxed().collect(Collectors.toSet()).size() == 1) {
}
or
if (Stream.of(a,b,c,d,e).collect(Collectors.toSet()).size() == 1) {
}
for general Objects.
A naive option is to build methods that receives all the variables as varargs and compare them one after other. If one of them is different you will get false
public static boolean areEqual(int...nums)
{
for (int i = 0 ; i < nums.length - 1 ; ++i) {
if (nums[i] != nums[i + 1]) {
return false;
}
}
return true;
}
Uses
if (areEqual(a, b, c, d, e))
I like this approach. There's no auto-boxing and no magic numbers.
As per the documentation, it's also short-circuiting so therefore potentially more efficient than other methods. More importantly, it's very easy to read.
IntStream.of(a, b, c, d).allMatch(x -> x == e);
Credit to saka1029.

About if statement in Java lang

i want to ask,can i insert an if statement into an if statement
i have a code like this:
if(some codes && some codes || (if(some codes) && some codes))
//then something else..
is it possible.i tried it but it gives an error.maybe its a syntax error maybe this is not possible if you answer i will learn :)
That's a syntax error.
If you have multiple conditions that you want to test, e.g. a, b, c and d, then combining them with logical operators in a single if statement should be enough, e.g.:
if (a && b || (c && d))
{
...
}
Depending on what you mean by
some codes
and
then something else
you might do fine with an if... else if
if(some codes && some codes )
// ...
else if((some codes) && some codes)
// ...
If "some codes" means you're using the body of the if to execute statements I'd suggest refactoring to make the code more readable.
If you want a conditional value, you can use the ?: notation in boolean context as follows
if(cond1 && cond2 || cond3 ? cond4 : cond5){...}
meaning if cond3==true evaluates to if(cond1&&cond2||cond4), else if(cond1&&cond2||cond5)
example
int a=1;
int b=2;
int c=3;
int d=4;
if(a!=b && b!=c || a+b==c ? a+c==d : b+c==d){
System.out.println("yup");
}else{
System.out.println("nope");
}

Categories

Resources