Java: Is "9" appearing in my run an Eclipse bug? - java

While writing my code for a computer dating assignment in which we see the compatibility of an array of four objects, my code printed strangely. (Eclipse didn't give me an error/warning at first).
Code:
System.out.print("Fit between " + profile1.getTitle() + " and " + profile2.getTitle() + ": \n " +
+ '\t' + profile1.fitValue(profile2) + '\n');
When I tried to print things out, they appeared like this:
Fit between Elizabeth Bennett and Elizabeth Bennett:
90.0
Fit between Elizabeth Bennett and Fitzwilliam Darcy:
90.55
Fit between Elizabeth Bennett and Romeo Montague:
90.3
Fit between Elizabeth Bennett and Juliet Capulet:
90.0
.......................................................so on so forth.
There was a "9" appearing in front of my numbers.
I found the problem later: I had two concatenating operators ("+") after my "\n". So I changed my code, deleting the extraneous "+".
New code:
System.out.print("Fit between " + profile1.getTitle() + " and " + profile2.getTitle() + ": \n " +
'\t' + profile1.fitValue(profile2) + '\n');
New correct run:
Fit between Elizabeth Bennett and Elizabeth Bennett:
0.0
Fit between Elizabeth Bennett and Fitzwilliam Darcy:
0.55
Fit between Elizabeth Bennett and Romeo Montague:
0.3
Fit between Elizabeth Bennett and Juliet Capulet:
0.0
..............................................so on so forth.
Though I've thankfully found my problem, I want to know what exactly is causing this to happen. Is there some sort of eclipse shorthand that leads to the "9"'s appearance? Or is this due to some eclipse bug? I'm still a beginner at java, so I can't make a solid conclusion.
I tried modifying my code slightly to see how Eclipse would react (I deleted the space between my original "+ +"):
System.out.print("Fit between " + profile1.getTitle() + " and " + profile2.getTitle() + ": \n " ++
'\t' + profile1.fitValue(profile2) + '\n');
Eclipse gave me this warning:
Multiple markers at this line
Syntax error on token "++", +
expected
Invalid argument to operation ++/--
This makes sense, because ++ on its own is an operator of sorts.
Interestingly, however, if I put a space between the "++", then the warning disappears.
I didn't paste my entire code for the sake of readability, but if necessary, I can edit and add it in.
Some clarification regarding this would be helpful. Thank you.

No, it's not a bug. It's unusual, but it's not a bug.
The first thing to do is simplify the example massively:
public class Test {
public static void main(String[] args) {
String start = "Start";
String end = "End";
System.out.println(start + '\t' + end);
System.out.println(start + +'\t' + end);
}
}
Result:
Start End
Start9End
Now admittedly I'm using strings for both start and end, but due to + being left-associative, that doesn't make any difference here. (If start were an integer, the first binary + operator would be integer addition in both cases.)
Basically, the extra + ends up being a unary + operator with '\t' as the operand. Unary numeric promotion is applied to the char, giving int as a result. So the code becomes effectively:
System.out.println(start + +((int)'\t') + end);
which is effectively:
System.out.println(start + +(9) + end);
which is effectively
System.out.println(start + 9 + end);
... at which point it's hopefully clear why you're getting the output you are.
To avoid accidentally ending up treating a character as an integer, it's probably best to just use strings instead - at which point the code won't compile because there's no unary + operator for String:
System.out.println(start + +"\t" + end);
... gives:
Test.java:6: error: bad operand type String for unary operator '+'

The problem is not just with the + + in your code. But it's also with the fact that you are using char '\t' and not String "\t".
So when you use System.out.println("Hello" + '\t');, the \t is taken as a character literal and appended to the string as \t.
But when you use System.out.println("Hello" + + '\t');, it becomes effectively System.out.println("Hello" + (+ '\t'));. So it is treated as an int by java. You only assign + and - signs to ints, not chars.
Remember you can do int i = +2 or -2 or + +2.
And the ASCII value of \t is 9. Hence it gets appended to the string and get's printed as Hello9.

You're using the char \t and not the string "\t" with the + operator so it is using the ascii numeric value of 9 for tab
so
System.out.println("\n"+ +'\t');
is the same as
System.out.println("\n"+ (+9));

I don't think this is a problem with eclipse. It works the same way on console also. The +'\t' is considered as integer value 9 by Java not as a Character.

Related

Identify special characters into a String that make it uncomparable with another String

I have a unit test where I compare an expected log file with an actual log file, if they are equals then the test is green.
The problem that I have is that when I perform the following comparison with JUnit:
assertEquals(expectedLogFile, reachedLogFile);
I get a junit.framework.ComparisonFailure as the two strings are not equal.
However, when I open the to see the difference, I see this:
That clearly looks like some special characters are coming into play, but I'm having a hard time identifying them.
Does anyone have any idea to spot the issue? I'll share below all the tests that I did so far.
Note: The two files are pretty large and hard to share here. If you need more input to provide with an answer, let me know and I'll try to see how I can share some more content here on S.O.
How do I build the reachedLogFile
In order to collect log lines, I inject a mock implementation of org.sl4j.Logger that collects each line called by the logger (.info(...), .debug(...), .error(...) etc.) into a synchronized list (because multiple threads write at the same time) and then transforms this content into a String like follows:
protected String retrieveLogSequence() {
return LOG_LINES.stream()
.map(l -> l.getLogLevel() + " - " + l.getMessage())
.collect(Collectors.joining(System.lineSeparator()))
.replace(WORKING_DIRECTORY, "AppDir")
.replace("\n", System.lineSeparator());
}
It shouldn't be relevant but l.getLogLevel() returns a simple enum DEBUG, TRACE, INFO, WARN, ERROR while l.getMessage() returns the message that was logged in the production code.
Just to give you an idea of what the content of the list LOG_LINES looks like:
How do I build the expectedLogFile
I have a file in my resources which already contains the expected content.
I read it like this:
File resource = new File("src/test/resources/" + resourceName);
String expectedLogFile = FileUtils.readFileToString(resource, StandardCharsets.UTF_8);
return expectedLogFile.replace("(slash)", File.separator);
Note: FileUtils is an external open-source dependency declared under commons-io:commons-io:2.6.
Where is the difference located?
So I added this sample function just for debugging purposes:
private void debugDifference(String reached, String expected) {
System.out.println("Reached string has " + reached.length() + " characters");
System.out.println("Expected string has " + expected.length() + " characters");
long smallerSize = Math.min(reached.length(), expected.length());
for (int j = 0; j < smallerSize; j++) {
if (reached.charAt(j) != expected.charAt(j)) {
System.out.println("Char[" + j + "] is \"" + reached.charAt(j) + "\" for reached and \"" + expected.charAt(j) + "\" for expected");
}
}
}
The first issue I can see is in the first two lines of the function, where I print the strings length. This is the output:
Reached string has 7590 characters
Expected string has 7622 characters
Apparently, there are some extra-characters on the "expected" string (meaning on the expected file, which by the way I simply copy-pasted from the debugger reachedLogFile so it must definitely be the way of reading it).
But no, it's not that. Instead, it seems there are some "disappearing/negative" characters in the reachedLogFile (sorry for the meaningless term but this really goes over my knowledge, please read further to understand what I mean).
Going further in my debug function, I can see that the differences begins around the 150th character but the console output I get is very weird:
" for reached and "
" for expected
Char[150] is "
" for expected
Char[151] is "I" for reached and "
" for expected
Char[152] is "N" for reached and "I" for expected
Char[153] is "F" for reached and "N" for expected
Char[154] is "O" for reached and "F" for expected
Char[155] is " " for reached and "O" for expected
Char[156] is "-" for reached and " " for expected
Char[157] is " " for reached and "-" for expected
Char[158] is "N" for reached and " " for expected
Char[159] is "o" for reached and "N" for expected
Char[160] is " " for reached and "o" for expected
Char[161] is "c" for reached and " " for expected
Char[162] is "o" for reached and "c" for expected
Char[163] is "n" for reached and "o" for expected
Char[164] is "f" for reached and "n" for expected
It's like the 149th character makes disappear the very first part of my System.out.println() (the part where I print "Char[" + j + "] is \"" + reached.charAt(j)) - it looks like it was some kind of carriage return like \r\n, but then why I don't see the first part of my message?.
This repeats few times in the whole comparison, justifying the difference of 11 characters between the two strings (see above when I print length() of both strings).
From time to time, there is this "weird" character appearing that breaks even the System.out.println.
Notepad++ in mode "Show all symbols"
Usually, IntelliJ comparator is capable to detect any special character but as shown in the above screenshot, it's not this time.
So when this happens, I usually use Notepad++ in mode "Show all symbols" which for me is like "if it can't, then nobody could".
And here I get another disappointment. From the few print lines that I posted above you can identify the sentence INFO - No configuration which is after just 150 characters in the two strings.
But in Notepad++, I don't see any difference at that point between the two files:

The purpose of double quotes ("") with integer concatenation

I just started the "Head First Java" book. There is an exercise that is tripping me up due to the double quotes ("") with no space in the code below. I think I figured it out, but it doesn't look like the book explains it and I would like to make sure I am correct moving forward.
Is the purpose of the double quotes ("") in the code below to concatenate the two integers (x and y) and prevent the + operator from performing addition for the output? That's what it seems.
The OUTPUT for the code below is: 00 11 21 32 42.
I deleted the double quotes and the output gives me: 0 2 3 5 6.
class Test
{
public static void main (String[] args)
{
int x = 0;
int y = 0;
while ( x < 5)
{
y = x - y;
System.out.print(x + "" + y + " ");
x = x + 1;
}
}
}
To answer your direct question: you are correct that the "" is there to turn the + into a concatenation, rather than addition. But I'll give a few more details as to what's going on here.
It's perhaps a little bad of the authors of the book to use this without explaining, since this appears to be a key thing in the exercise (even a brief footnote saying "this is just an easy way to convert to a String"); but it's one of those things most Java programmers wouldn't even think about needing to explain, so easy to miss; or, perhaps they did explain it earlier, and you just missed it, because of the throw-away nature of the explanation. No accusations; it's just what it is.
We're trying to evaluate the expression x + "" + y + " " in order to print it. Because + is left-associative, this is evaluated as
((x + "") + y) + " "
So, in terms of the effect of including "", the question is how the subexpression x + "" will be evaluated. If the "" had been omitted, it would be evaluated as
(x + y) + " "
There is no separate operator for "numeric addition" and "string concatenation" in Java: both use +. So, Java uses a simple rule to decide between the two:
If the type of either operand of a + operator is String, then the operation is string concatenation.
As such, x + "" is string concatenation, but x + y would be numeric addition.
If you look into the specifics of string concatenation:
If only one operand expression is of type String, then string conversion (ยง5.1.11) is performed on the other operand to produce a string at run time.
So this is saying that the int in int + String has to be converted to a string, in order to concatenate it with another string, which is pretty reasonable. And this string conversion is done using:
If T is byte, short, or int, then use new Integer(x).
...
the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments
("as if" is just wiggle room to say you don't actually have to invoke new Integer(x) - implementations could use Integer.toString(x), or some other method, instead).
Then, concatenation is defined as:
The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string.
Given that "" has no characters, it is trivially true that someString + "" will have the same characters as someString (*).
So, int + "" (or "" + int) is simply a syntactic trick to convert the int to a String. There is no other effect of doing this. It's just less verbose to write this than Integer.toString(x) or new Integer(x).toString().
It's also worth pointing out that it would work the same had it been "" + x + y + " ". But that's perhaps less clear to the human eye that the x and y won't be added.
(*) The slight detail here is that concatenation results in a new string (unless the two operands are constant expressions, in which case the concatenation is done at compile time), i.e. someString + "" != someString, even though (someString + "").equals(someString).
Is the purpose of the double quotes ("") in the code below to
concatenate the two integers (x and y) and prevent the + operator from
performing addition for the output?
That's exactly what it is. The alternative would be something like
print(String.valueOf(x) + String.valueOf(y) + " ")
which is a lot less readable. The String type can be forced also in the beginning, as in "" + x + y + " ", just as long as we're dealing with Strings before we start to use the + operator.

Why use " " and not ' ' for outputting a blank? [duplicate]

This question already has answers here:
Is there a difference between single and double quotes in Java?
(4 answers)
Closed 3 years ago.
Is there any reason why you may want to use " " and not ' ' to output blanks in Java (any version)?
In "Data Structures and Problem Solving Using Java (4th Edition)" by Mark Allen Weiss, it says that it is a common error to not use " " instead of ' ': i.e. We should use " ".
As far as I know, there are no differences between the two.
Trying:
System.out.println("a b c" + ' ' + "d e f");
System.out.println("a b c" + " " + "d e f");
There seems to be no difference in the output.
With your example if may have no effect. However, there are cases where it matters.
char is an integral type, and
System.out.println(1 + ' ' + 2); //output: 35 because 1 + 32 + 2
produces a different result from
System.out.println(1 + " " + 2); //output: 1 2
So you should make sure you know the difference between ' ' and " ".
I imagine that the context of the advice in the book gives some indication of what situation it is talking about.
It is because + operator has two meanings in Java
concatenation if at least one operand is String like Str + ... or ... + Str
addition if both operands are numeric types:
all primitives, except boolean (no in Java true and false are not equivalents of 1 and 0),
BUT including char which numeric value is position of character in Unicode Table like 'A' is 65 and space ' ' is 32.
wrapper classes for numeric primitive types like Integer, Double
So if you have num + Str operator + will represent concatenation and you will get String.
But in case of num + char operator + will represent addition and will return numeric value like System.out.println(1+' ') will be treated as 1+32 so 33 will be printed.
So if you use " " with + you are guaranteed that it will be concatenation, while meaning of + with ' ' will depend on second argument.
We use single quotes for literal chars and double quotes for literal Strings. So you're going to add them together with this:
System.out.println("a b c" + ' ' + "d e f");
but there is no error in it. You can use " " or ' ' to output a space.
The reason your Java book tells you that double quotes is better than single quotes is that ' ' is a char, and " " is a String. This is built-in java behaviour.
char is a java primitive, like an int or a float. String is a supplied object type, not a primitive. When you put " " in your code, java interprets this as an instance of java.lang.String.
You're right that it has no practical effect in your example though. That's because when you concatenate strings and characters, java automatically converts the whole thing to a String (the + operator does this). You can also concatenate other primitives in this way.
However, these are actually quite different in Java, and you can prove this with a simple test:
#Test
public void testCharVsString(){
assertTrue(" ".equals(' '));
}
The above test will fail, as these two objects are not the same.
As a general rule it's OK to stick with Strings when representing characters. char is useful for more advanced coding tasks.

Issue with printing space with single quotes in a int array in Java

I want to print my int[] in a specific format (within space between each numbers, etc)
However I found Java does not print the spaces in the single quotes, and it even change my numbers in the int[]. Same things happened to the bracket character.
For example:
int[] test = {1,2,3,4,5};
System.out.println('(' + test[0]+ ' ' +test[1] + ' ' + test[2] + ' '
+test[3] + ' ' + test[4] + ')');
//224
System.out.println("(" + test[0]+ " " +test[1] + " " + test[2] + " "
+test[3] + " " + test[4] + ")");
//(1 2 3 4 5)
I think space and bracket are characters, and I wonder why I need to use double quotes to print them properly and why the single quotes with space character would change the output?
Thank you!
Quoting with apostrophes is a char literal. A char is a numeric primitive, and can be added to other numeric primitives like int.
The + operator is also overloaded to implement string concatenation. If either side of the operator is a String, the + operator is a string concatenation operator, otherwise it is a numeric add operator.
So, 'A' + 5 means add 5 to the numeric value of character A, while "A" + 5 means concatenate the string A with the string representation of the number 5.
In your case, it would have been enough to change the first character into a String literal. All the remaining + operators would then become string concatenation operators:
System.out.println("(" + test[0] + ' ' + test[1] + ' ' + test[2] + ' '
+ test[3] + ' ' + test[4] + ')');
//(1 2 3 4 5)
The reason is, characters are fundamentally stored as numbers. When you add characters together with other numbers, you'll receive a number as a result.
// Prints 97
System.out.println('a' + 0);
The only situation where characters will not be added as a number is when they're added to a string.
System.out.println("Letter" + 'a');
In your code above, you only add numbers and characters together, so you get a number as output. Java adds things from left to right, so by changing the first-appearing character to a string, you should get your desired output.
// Fixed version
System.out.println("(" + test[0]+ ' ' +test[1] + ' ' + test[2] + ' '
+test[3] + ' ' + test[4] + ')');
Single quoting in Java means a char type, whereas the double-quote means a String type. So your first line is trying to print the values of those chars. See here https://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html#println() for the overloaded methods.

What happens if you remove the space between the + and ++ operators?

EDIT 1
DISCLAIMER: I know that +++ is not really an operator but the + and ++ operators without a space. I also know that there's no reason to use this; this question is just out of curiosity.
So, I'm interested to see if the space between + and ++var is required in Java.
Here is my test code:
int i = 0;
System.out.println(i);
i = i +++i;
System.out.println(i);
This prints out:
0
1
which works as I would expect, just as if there were a space between the first and second +.
Then, I tried it with string concatenation:
String s1 = "s " + ++i;
System.out.println(s1);
// String s2 = "s " +++i;
This prints out:
s 2
But if the third line is uncommented, the code does not compile, with the error:
Problem3.java:13: unexpected type
required: variable
found : value
String s2 = "s " +++i;
^
Problem3.java:13: operator + cannot be applied to <any>,int
String s2 = "s " +++i;
^
What's causing the difference in behavior between string concatenation and integer addition?
EDIT 2
As discussed in Abhijit's follow-up question, the rule that people have mentioned (the larger token ++ be parsed first, before the shorter token ++) is discussed in this presentation where it appears to be called the Munchy Munchy rule.
There is no +++ operator. What you have there is a postfix ++ operator followed by an infix + operator. That is a compilation error because postfix ++ can only be applied to a variable, and "s " isn't a variable.
Since you really mean an infix + operator followed by a prefix ++ operator, you need to put the space in between the operators.
Actually, you should do it ANYWAY. +++ is a crime against readability!!!
Compiler generates longest possible tokens when parsing source, so when it encounters +++, it takes it as ++ +.
So the code of
a +++ b
Will always be same as
(a++) + b
The triple plus is not an operator itself, it is two operators combined:
What the triple plus acutually does is:
a+++1 == a++ + 1;
What you are trying to do is ++ a String, which is undefined.
Never ever use +++ without spaces in your code; hardly anyone will know what it does (without consulting web). Moreover, after a week or so, you will not know what it actually does yourself.
+++ isn't an operator by itself.
i = i +++i; results in a pre-increment value of i, then adding it to the value of i and storing it in i.
With the String, + doesn't mean addition, so you're attempting to concatenate the string and the integer together.

Categories

Resources