I saw a question on Java manuals that keeps grinding my gear so i'm posting it here to solve it once and for all.
The question is:
If n and k are int type then what type would ' n > k && k < 0 ' expression be?
Possible answers : byte, boolean, int, double, won't compile.
Thank you for your advice on it.
An easy way to check is just to print it using for example Ideone. Check this link to see a demonstration.
That said, the expression evaluates to a boolean. Since < and > have higher precedence than &&, the expression is equivalent to (n > k) && (k < 0), which is a bit easier to interpret.
boolean
This expression is usually used in a condition and return true or false.
It is boolean because : (n > k && k < 0)
n > k return boolean
k < 0 return boolean
boolean && boolean is boolean
Related
I have a very simple java class to solve Decode ways using recursive approach. I am seeing this weird behavior of conditional operator,
package decodeways;
public class Solution {
public static void main(String[] args) {
System.out.println(numDecodings("1456"));
}
public static int numDecodings(String s) {
if(s.length()>0 && s.charAt(0)=='0')
return 0;
if(s.length()==0) return 1;
if(s.length()==1)
return 1;
int num1 = s.charAt(0)-'0';
int num2 = s.charAt(1)-'0';
int one = numDecodings(s.substring(1));
int two = s.length()>1?numDecodings(s.substring(2)):0;
int res = one
+ num1<3 && num2<7 ? two:0;
return res;
}
}
if I put a parentheses, (num1<3 && num2<7 ? two:0) then everything is well and good but if I remove the parentheses, then getting incorrect results.
during the process of debugging, one will be computed to 1 and two will be computed to 1 and res will be 1 as well with parentheses but without it, the computed result of res will be 0 (screnshot attached) which is the source of error.
I am aware of the operator precedence in java, but in this situation I can't figure out why it shows incorrect behavior, because in the below code:
int res = one
+ num1<3 && num2<7 ? two:0;
one + num1<3 is illegal
So, java is intelligent enough to not confuse between (one + num1<3) and (num2<7 ? two:0) to be consider separately.
So, as per my understanding the only legal observable behavior for java compiler is to automatically consider num1<3 && num2<7 ? two:0 as an atomic operation(Please correct me if I am wrong), irrespective of parentheses is available or not.
Please guide me to have a better understanding.
Thanks.
int res = one
+ num1<3 && num2<7 ? two:0;
is equivalent to
int res = (((one + num1) < 3) && (num2 < 7)) ? two : 0;
Everything before ? is included in the boolean expression, since the ternary/conditional operator has the lowest precedence here (not including the assignment operator) and + has the highest.
The order goes something like:
+, so one + num1 is put together first
<, so now there's (one + num1) < 3 and num2 < 7
&&, after which you have ((one + num1) < 3) && (num2 < 7)
and finally ?:
You seem to be expecting the newline to make the compiler think one and num1<3 && num2<7 ? two:0 are separate, but it actually just ignores all whitespace. Putting the parentheses there is the only way to make sure one is added to the whatever the conditional operator evaluates to.
int res = one + (num1 < 3 && num2 < 7 ? two : 0);
I'm changing some C code into Java, but I have come across a statement syntax that I have not seen before and I don't know what it means.
for (unsigned int i = 0; i < SIZE; i++)
{
count[2 * SIZE + 1] += grid[i][SIZE - 1 - i] != 0;
}
When adding elements of two arrays, I've never seen '!= 0' come after it. Do you know what this statement is doing? I can't find any reference to this online.
Any help is appreciated.
grid[i][SIZE - 1 - i] != 0 is a boolean expression which (by the C standard) is evaluated to 1 if the expression is true, 0 otherwise.
The same thing can be written as following:
for (unsigned int i = 0; i < SIZE; i++)
{
if ( grid[i][SIZE - 1 - i] != 0)
{
count[2 * SIZE + 1] += 1;
}
}
Unlike in C/C++, in Java, the result of this test is a boolean not an integer (0/1), and you cannot add a boolean so it counts for 0 for false or 1 for true.
I suggest a simple test which avoids to add 0 to count uselessly. So probably faster (well, constant branching could make it slower, has to be benched) & less cryptic (that's a fact), and valid in C, C++ or Java:
if (grid[i][SIZE - 1 - i] != 0)
{
count[2 * SIZE + 1]++;
}
Booleans can be implicitly converted to integers.
It is equivalent to
(grid[i][SIZE - 1 - i] != 0) ? 1 : 0
that is, add 1 if the condition is true and zero otherwise.
If I change the else if portion of this code to an else statement it runs without any problems so I get how to make it run. What I'm a little confused about is why I get a missing return statement error when it is in its current form. My return is dependent on the value of the boolean variable of negative. I covered the true and false states, isn't that good enough to cover everything?
Or is it that I always have to have a return statement within an else or to add a meaningless return true to the bottom of my function for the compiler to accept my code as covering every case?
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
else if (negative) {
return (a < 0 && b < 0);
}
}
public static void main (String[] args) throws java.lang.Exception
{
}
}
When the compiler sees else if without an else or a trailing return statement, it cannot be certain that all control paths will lead to a valid return statement.
The compiler can be smart at times, but it can't be smart in this situation (nor should it be).
This behavior is helpful in your example: there's absolutely no reason for you to use an else if in this situation. A simple else is easier to read, more concise, and less error prone.
An else is very expressive in this case. It means "the opposite of the if clause" which will still be the case if the code changes in the future.
Your current code would be more likely to contain and/or introduce a bug if the compiler allowed it.
Here's how I would rewrite the method body:
if (negative) {
return (a < 0 && b < 0);
}
else {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
In general you should prefer if (negative) over if (!negative) unless there's a compelling reason (ie readability) to do otherwise.
Also, a lot of people (including myself) try to put the most simple clause first in an if/else statement. Making your code easy to read is a good thing.
Check out StephenC's answer for a technical explanation and more background about why the compiler behaves this way.
Other questions have explained what the error message means from an intuitive perspective. However the "The compiler is smart, but not perfect!" comment is missing the point.
In fact, the Java compiler is calling your example an error because the Java Language Specification requires it to call it an error. The Java compiler is not permitted to be "smart" about this.
Here is what the JLS (for Java 71) actually says, and how it applies to a simplified version of the incorrect example, and then a corrected version.
"If a method is declared to have a return type, then a compile-time error occurs if the body of the method can complete normally (JLS 14.1). In other words, a method with a return type must return only by using a return statement that provides a value return; it is not allowed to "drop off the end of its body". " - JLS 8.4.7
(Read JLS 14.1 for the definition of "normal completion" ...)
And the rules for deciding whether a "normal" completion is possible are the reachability rules in JLS 14.21. And they say:
"An if-then statement can complete normally iff it is reachable."
"An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally."
"A break, continue, return, or throw statement cannot complete normally."
(Where 'iff' means "if and only if" ...)
Consider a simplified version of the example:
public int test(boolean a) {
if (a) {
return 1;
}
else if (!a) {
return 0;
}
}
In this example, the else-statement is an if-then which can complete normally by rule #1. Therefore, by rule #2, the if-then-else statement can also complete normally. But that is a compilation error, because JLS 8.4.7 says that a method with a return type cannot complete normally.
But if you change the example to this ...
public int test(boolean a) {
if (a) {
return 1;
}
else {
return 0;
}
}
Now by rule #3, both the if-statement and the else-statement cannot complete normally. So by rule #2, the entire if-then-else cannot complete normally. That is what it required by JLS 8.4.7 ... therefore no compilation error.
1 - The Java 8 JLS will say essentially the same thing, though the section numbers may be different ...
I think you already know that the second if is redundant.
if (negative) is interpreted context-free, which means that the compiler ignores that if(!negative) has already been handled.
if => else if => where is the else condition?
For a return statement, all branches (conditions) must be handled.
You could do:
if (!negative)
return (a < 0 && b > 0) || (a > 0 && b < 0);
return (a < 0 && b < 0);
or:
if (!negative)
return (a < 0 && b > 0) || (a > 0 && b < 0)
else
return (a < 0 && b < 0);
or (my preferred way):
return negative ? (a < 0 && b < 0) : (a < 0 && b > 0 || a > 0 && b < 0)
However, I'd recommend to avoid the negative condition, it's harder for the human brain in complex scenario. Even some Java IDEs like IntelliJ helps to find those patterns to fix them.
You'd end up with:
if (negative)
return (a < 0 && b < 0);
else
return (a < 0 && b > 0) || (a > 0 && b < 0);
You do not need "if (negative) {}" in the "else" brace
You should have a return in all your branches.
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
else if (negative) {
return (a < 0 && b < 0);
}
}
The method above logically has a return in all branches, but technically it does not. We like the Java compiler to be fast, therefore it is undesirable to have a Java compiler analyzing semantically the code.
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
else {
return (a < 0 && b < 0);
}
}
The method above has a return in all the branches.
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
return (a < 0 && b < 0);
}
However, as you can see above, you do not even need the else, because if the code ever reaches the second return, then negative is certainly false, as if it was true, the first return would end the algorithm.
public boolean posNeg(int a, int b, boolean negative) {
return ((negative) && (a < 0 && b < 0)) || ((!negative) && (a < 0 && b > 0) || (a > 0 && b < 0));
}
The method above is a one-liner.
public boolean posNeg(int a, int b, boolean negative) {
return ((negative) && (a < 0 && b < 0)) || ((!negative) && ((a < 0) == (b > 0)));
}
The method above uses the fact that in the second case the positivity of a is equal with the negativity of b.
What would be the most terse way in Java to check for the following condition
int m, n;
The condition to check is whether either m or n are negative but both shouldn't be negative. I'm looking for a terse yet simple syntax
(m < 0) ^ (n < 0)
Note that in this context, ^ is the logical XOR operator (yes, I do mean "logical", distinct from "bitwise").
(m ^ n) < 0
Even more filler to make an appropriate length answer.
I'd go for:
(m < 0) != (n < 0)
!= operates the same as ^ for booleans, but I think it's easier to understand and more commonly used.
Basically your test should be - the sign bit (highest order) shound be different.
Here is the test expressed in java;
if ( (x & Integer.MIN_VALUE) != (y & Integer.MIN_VALUE) )
...
Why when comparing a char against another it must be taken also from a string? For example;
This does not work
while(i < t.length() && zeroCount < 5) {
if(t.charAt(i) == 0){
zeroCount++;
}
i++;
}
Nor does this
char zero = 0;
while(i < t.length() && zeroCount < 5) {
if(t.charAt(i) == zero){
zeroCount++;
}
i++;
}
The only way I managed to get it working is like this...
String zeros = "0000000000";
while(i < t.length() && zeroCount < 5) {
if(t.charAt(i) == zeros.charAt(i)){
zeroCount++;
}
i++;
}
Can anyone explain if am doing something wrong, or if it is just not acceptable to do it like the top 2 examples. If so, why?
You're confusing
char zero = 0;
with
char zero = '0';
The former is the null-character (ASCII value of zero), whereas the latter is the character representing the digit zero.
This confusion is a rather unfortunate hang-over from C, with char variables being treated as numbers as well as characters.
You are looking for the character '0'? Then compare to '0', not 0.
You're comparing against Unicode value 0 (aka U+0000, the "null" character) - which is not the same as the Unicode character representing the digit 0.
Use '0' instead of 0:
while(i < t.length() && zeroCount < 5) {
if(t.charAt(i) == '0'){
zeroCount++;
}
i++;
}
Use '0' instead of 0.
The simple answer is that the value 0 is not the same as the character '0' which has an ASCII code of 48 (IIRC).
You should compare it with the char value charAt(i) == '0' or subtract the char before comparison charAt(i) - '0' == 0
These other answers have it right, but there’s one very important thing you should know. You should never use chatAt! You should only use codePointAt.
Similarly, you mustn’t blindly use i++ to bump through a string. You need to see whether s.codePointAt(i) > Character.MAX_VALUE to know whether to give an extra i++ kicker.
For example, to print out all the codepoints in a String s in standard "U+" notation:
private static void say_U_contents(String s) {
System.out.print("U+");
for (int i = 0; i < s.length(); i++) {
System.out.printf("%X", s.codePointAt(i));
if (s.codePointAt(i) > Character.MAX_VALUE) { i++; } // UG!
if (i+1 < s.length()) { System.out.printf("."); }
}
}
That way you can output like U+61.DF, U+3C3, and U+1F4A9.1F4A9 for the corresponding strings. That last one looks like "\uD83D\uDCA9\uD83D\uDCA9", which is simply insane.