Why trim() give me String Constant Pool reference? - java

I am exploring String Constant Pool and Heap memory.
if("String".trim() == "String")
System.out.println("Equal");
else
System.out.println("Not Equal");
Output
Equal
And If I add a space in the String before trim, It will give Not Equal output
if("String ".trim() == "String")
System.out.println("Equal");
else
System.out.println("Not Equal");
Output
Not Equal
Can you explain me above scenario?
And How can I see Heap Memory and String Constant Pool?

The (Java 8) javadocs for String.trim() state:
Returns: A string whose value is this string, with any leading and trailing white space removed, or this string if it has no leading or trailing white space.
Since "String" has no leading or trailing spaces, trim() is returning the "String" object.
On the other hand "String " has trailing spaces, so a different String object is returned1.
BTW: It is not called the "string constant pool". All strings are constant (immutable). You might be be talking about all strings that are the result of the evaluation of a compile time constant expression. However, the string pool can also contain strings that were added by a String.intern() call on a dynamically created string. The correct term is the "string pool".
1 - It happens that this object is a different object to the one that represents the "String". However, a careful reading of the javadoc will reveal that the spec does not require this to be the case. In a different (hypothetical) version of Java, the trim() method could return the "String" object and still conform to the spec.

trim() method can return the same instance or a totally new created string object, you can verify that in the source code of the method:
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
so it will depends wether this condition meet or not
((st > 0) || (len < value.length))
now when you do: "String".trim() == "String" the condition doesnt meet so you will compare the reference of the literal "String"
on the option left, a new object is created and the comparison using == returns false....

The second example shows "Not Equal" because,
The method trim() returns a copy of this string with leading and trailing white space removed, or this string if it has no leading or trailing white space.
The word copy is important.

Strings are objects, so comparing Strings with == is not the right choice. Trim returns a String, then you need to compare it to another String using equals, even if the string is not wrapped into a variable. Try using:
System.out.println(" this is a string ".trim());
String test = " this is a string ";
System.out.println(test.trim());
both are going to give the same answer: "this is a string"
I your case you should use:
"string".trim().equals("string")
which will give you the right answer.

Related

Java checking array contents

The problem I am having is using .contains() for an array. This is my current line of code:
if (strings[i].contains(symbol) = true){
strings[] is an array that stores user inputted data, the error message i get for this is "The left-hand side of an assignment must be a variable". I understand what this means, my question is, can I use one string from the array when using .contains() or am I going about this the wrong way?
Any help will be appreciated. Thanks.
The problem is that
strings[i].contains(symbol) = true
is an assignment because of the =. You probably mean
strings[i].contains(symbol) == true
and, because the left hand side is a boolean,
strings[i].contains(symbol)
is already sufficient.
my question is, can I use one string from the array when using .contains()
If you read the Java API for String (http://docs.oracle.com/javase/7/docs/api/java/lang/String.html), contains() is a method from String class.
By knowing that, you can use .contains() on a single String element / a String variable.
String str = "abc";
str.contains(symbol); //This is ok.
String[] strs = {"abc", "def"};
str[0].contains(symbol); //This is ok too.
Both of the above are allowed, because both are String.
String[] strs = {"abc", "def"};
str.contains(symbol); //This is wrong!
One more thing which you should have noted by now in your codes is:
When comparison, use == and not single =
And when comparing strings or objects, use .equals()
Of course, you can also write it as:
if(strings.[i].contains(symbol)) //if this statement is true
if(!strings.[i].contains(symbol)) //if this statement is not true
instead of
if(strings.[i].contains(symbol) == true) //if this statement is true
if(strings.[i].contains(symbol) == false) //if this statement is not true

How does the comparison in Strings work? [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
String comparison - Android [duplicate]
(17 answers)
Closed 8 years ago.
When I compare ("String"=="String"), what exactly I am comparing, the two objects or two references?
Please explain the output of following code snippets:
1) System.out.println("String".toString()=="String"); // output is true
2) System.out.println("String".trim()=="String"); // output is true
3) System.out.println("String ".trim()=="String"); // output is false
According to statement 1 and 2, the output of 3rd statement should also be true. Please explain what is going on here.
From my previous answer, You have to remember, == compares the object references, not the content.
trim() returns a copy of this string with leading and trailing white space removed, or this string if it has no leading or trailing white space.
in the first case the answer is true no surprise about that because the references are equal
in the second case there are no leading or trailing spaces so trim returns the same string again the references are equal
in the last case trim returns a copy as the string has a trailing white space which results in a different reference so your comparison will be false.
In java you should never compare strings with the equality operator ==, since that operator compares references rather than contents. The compiler is smart enough to reuse one reference for all equal literals found in the code (so the four occurrences of String in 1) and 2) are probably the same instance). However in 3) you have two different literals and there is no guarantee that "String ".trim() will be represented by the same instances as the literals.
See also: https://stackoverflow.com/a/513839/55787
Use .equals() instead.
== compares whether the two String references you are comparing point to same String instance or not.
To answer your question you need to check the source code of methods in String class
public String trim() {
int len = count;
int st = 0;
int off = offset; /* avoid getfield opcode */
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[off + st] <= ' ')) {
st++;
}
while ((st < len) && (val[off + len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < count)) ? substring(st, len) : this;
}
public String toString() {
return this;
}
As you can see it return this in case of trim if there is nothing to trim which is why you get true. Also toString simply returns this.
you have to use the method
equals()
to compare Strings. Instead with == you are comparing
references.
== compares memory location . In the first case , the toString method returns the same object ,and since both "String" objects being compared point to the same object on the constant pool, the result is true. In the second case, the trim method does no modification to the String so it returns the same object, with the same result. The third case and the second call to trim returns a different object, not located on the constant pool

Why my below code of String Comparison is not showing what i am expecting in java [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
if("String ".intern().trim()=="String"){
System.out.println("Equals");
}else{
System.out.println("Unequal");
}
above code is showing Unequal. I don't understand why? Can someone explain it?
I'm not really sure what you're facing, but if you want to compare the addresses of the strings by using the intern() method, this will also work:
if ("String ".trim().intern() == "String") {
System.out.println("Equals");
} else {
System.out.println("Unequal");
}
You only have to swap the trim() and intern() calls.
intern() searches for the string which is already on the heap and addresses this. When you use the == to compare the strings, the addresses will be equal.
For better visualization:
Value Evaluates to Address Explanation
"String" "String" 1 Creates new "String"
"String " "String " 2 Creates new "String "
"String ".trim() "String" 3 trim() creates new "String"
"String ".trim().intern() "String" 1 intern() finds the already created "String"
"String ".intern() "String " 2 intern() finds the already created "String "
"String ".intern().trim() "String" 4 trim() creates new "String"
That's also because trim() is generating a new String().
To try by yourself:
public class StringCompare {
public static void main(String[] args) {
System.out.println(System.identityHashCode("String"));
System.out.println(System.identityHashCode("String "));
System.out.println(System.identityHashCode("String ".trim()));
System.out.println(System.identityHashCode("String ".trim().intern()));
System.out.println(System.identityHashCode("String ".intern()));
System.out.println(System.identityHashCode("String ".intern().trim()));
}
}
Will output something like:
1500673861 // 1
1777631459 // 2
859434349 // 3
1500673861 // 1
1777631459 // 2
538093921 // 4
You need to know that String literals are placed in string pool by default like
String s = "Hello";//this will be in string pool
but Strings created at runtime via new String(...) are not by default placed or retrieved from this pool.
String s2 = new String(s);// or even `new String("Hello")`
System.out.println(s == s2);// returns false, which means s2 holds different String
// object then from String pool
Now substring returns new String(...) objects, so it means they are not from String pool.
trim uses substring method internally which if
range specified to substring will be different than from 0 till length will return new String object with characters from specified range
range is from 0 till strings length (ideally covers entire string) returns same String with return this;
So in your code you are trying to place "String " in string pool (which you don't have to do, because you are using String literal "String " which is already placed in pool), Then you are using trim method on this object so since there is part to trim, it will create and return new String, different from original, and definitely not from String pool so comparing it with "String" literal with == will return false.
"String".intern() creates a different instance of String stored in permgen or metaspace while the original instance is stored on regular heap. Therefore your comparison will always be false.
Always compare strings using equals()method!!!
Try something like this:
if("String ".trim().equals("String")){
System.out.println("Equals");
}else{
System.out.println("Unequal");
}
Useful Link
==, .equals(), compareTo(), and compare()
Comparing Strings and Portions of Strings
When should we use intern method of String on String constants (Example On Stack Overflow)

Behavior of String literals is confusing

The behavior of String literals is very confusing in the code below.
I can understand line 1, line 2, and line 3 are true, but why is line 4 false?
When I print the hashcode of both they are the same.
class Hello
{
public static void main(String[] args)
{
String hello = "Hello", lo = "lo";
System.out.print((Other1.hello == hello) + " "); //line 1
System.out.print((Other1.hello == "Hello") + " "); //line 2
System.out.print((hello == ("Hel"+"lo")) + " "); //line 3
System.out.print((hello == ("Hel"+lo)) + " "); //line 4
System.out.println(hello == ("Hel"+lo).intern()); //line 5
System.out.println(("Hel"+lo).hashCode()); //hashcode is 69609650 (machine depedent)
System.out.println("Hello".hashCode()); //hashcode is same WHY ??.
}
}
class Other1 { static String hello = "Hello"; }
I know that == checks for reference equality and check in the pool for literals. I know equals() is the right way. I want to understand the concept.
I already checked this question, but it doesn't explain clearly.
I would appreciate a complete explanation.
Every compile-time constant expression that is of type String will be put into the String pool.
Essentially that means: if the compiler can (easily) "calculate" the value of the String without running the program, then it will be put into the pool (the rules are slightly more complicated than that and have a few corner cases, see the link above for all the details).
That's true for all the Strings in lines 1-3.
"Hel"+lo is not a compile-time constant expression, because lo is a non-constant variable.
The hash codes are the same, because the hashCode of a String depends only on its content. That's required by the contract of equals() and hashCode().
Strings computed by concatenation at runtime are newly created and therefore distinct
here is a link to read: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
String object can be created in the following ways:
String str = new String("abcd"); // Using the new operator
// str is assigned with "abcd" value at compile time.
String str="abcd"; // Using string literal
// str is assigned with "abcd" value at compile time.
String str="ab" + "cd"; // Using string constant expression.
// str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1; // Using string expression.
// str is assigned with "abcd" value at run time only.
and Hashcode will be calculated only at runtime based on the contents of the String objects.
It's because the comipler in this instance is not smart enough to work out that it can burn in the same string literal.
Hashcode needs to always return the same value for strings that are equivelent (calling .equals on it returns true) so will return the same result.
Its because following code
("Hel"+lo)) + " "
is translated internally to
new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()
So you can see that entirely a new String instance is created with help of different String instances. That is why you get false as they point to different memory locations in heap
The hashCode doesn't have anything to do with an objects reference (The == check is a reference comparator). Its possible to have 2 objects where the hashCode returns the same value, the equals operator returns true, but == returns false. This is when they are 2 different objects, but with the same value.
I believe the reason line 4 is returning false is that it is a value computed at runtime, and thus is a different string instance, with a different reference.
String literals are saved in a special memory, if they are exactly the same, they are pointed to the same map of memory. If you don't create a literal String, a new object will be created so it won't point to that memory so the reference won't be the same.
The intern() method tells the virtual machine to put it into that shared, string literals map of memory so next time you do that literal, it'll search there and point it.
As you already know ... this is just because of reference ...when string comes from the pool it will have same refrence ...but when u do manuplations a new string with new refrence is generated ...
You can check this link for pooling concept
The difference between line number 3 and 4 are as follows.
•Strings computed by constant expressions are computed at compile time and then treated as if they were literals.
•Strings computed by concatenation at run time are newly created and therefore distinct.
The above reference is taken from java spec. Please let me know if you need more clarification.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
System.identityHashCode() would be returned by the default method hashCode(), this is typically implemented by converting the internal address of the object into an integer.
Finally I know the answer !
Read Java SE 8 specification section 15.21.3 Reference Equality Operators == and != (http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3)
While == may be used to compare references of type String, such an
equality test determines whether or not the two operands refer to the
same String object.
The result is false if the operands are distinct
String objects, even if they contain the same sequence of characters(§3.10.5). The contents of two strings s and t can be tested for
equality by the method invocation s.equals(t).
So the following code :
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
The expression ("Hel"+lo) in line 3, return the new Strings that computed by concatenation at run time.
*Strings computed by concatenation at run time are newly created and therefore distinct.
(http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634)
So the result of this code:
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
would result:
false
Because,
the "Hello" object in this expression:
String hello = "Hello";
and ("Hel"+lo) object in this expression:
System.out.print((hello == ("Hel"+lo)) + " ");
is different, although :
*they both contain the same sequence character, which is "Hello".
*they both have the same hashCode.
*hello.equals(("Hel"+lo)) will return true.

How do I check that a Java String is not all whitespaces?

I want to check that Java String or character array is not just made up of whitespaces, using Java?
This is a very similar question except it's Javascript:
How can I check if string contains characters & whitespace, not just whitespace?
EDIT: I removed the bit about alphanumeric characters, so it makes more sense.
Shortest solution I can think of:
if (string.trim().length() > 0) ...
This only checks for (non) white space. If you want to check for particular character classes, you need to use the mighty match() with a regexp such as:
if (string.matches(".*\\w.*")) ...
...which checks for at least one (ASCII) alphanumeric character.
I would use the Apache Commons Lang library. It has a class called StringUtils that is useful for all sorts of String operations. For checking if a String is not all whitespaces, you can use the following:
StringUtils.isBlank(<your string>)
Here is the reference: StringUtils.isBlank
Slightly shorter than what was mentioned by Carl Smotricz:
!string.trim().isEmpty();
StringUtils.isBlank(CharSequence)
https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#isBlank-java.lang.CharSequence-
If you are using Java 11 or more recent, the new isBlank string method will come in handy:
!s.isBlank();
If you are using Java 8, 9 or 10, you could build a simple stream to check that a string is not whitespace only:
!s.chars().allMatch(Character::isWhitespace));
In addition to not requiring any third-party libraries such as Apache Commons Lang, these solutions have the advantage of handling any white space character, and not just plain ' ' spaces as would a trim-based solution suggested in many other answers. You can refer to the Javadocs for an exhaustive list of all supported white space types. Note that empty strings are also covered in both cases.
This answer focusses more on the sidenote "i.e. has at least one alphanumeric character". Besides that, it doesn't add too much to the other (earlier) solution, except that it doesn't hurt you with NPE in case the String is null.
We want false if (1) s is null or (2) s is empty or (3) s only contains whitechars.
public static boolean containsNonWhitespaceChar(String s) {
return !((s == null) || "".equals(s.trim()));
}
if(target.matches("\\S"))
// then string contains at least one non-whitespace character
Note use of back-slash cap-S, meaning "non-whitespace char"
I'd wager this is the simplest (and perhaps the fastest?) solution.
If you are only checking for whitespace and don't care about null then you can use org.apache.commons.lang.StringUtils.isWhitespace(String str),
StringUtils.isWhitespace(String str);
(Checks if the String contains only whitespace.)
If you also want to check for null(including whitespace) then
StringUtils.isBlank(String str);
Just an performance comparement on openjdk 13, Windows 10. For each of theese texts:
"abcd"
" "
" \r\n\t"
" ab "
" \n\n\r\t \n\r\t\t\t \r\n\r\n\r\t \t\t\t\r\n\n"
"lorem ipsum dolor sit amet consectetur adipisici elit"
"1234657891234567891324569871234567891326987132654798"
executed one of following tests:
// trim + empty
input.trim().isEmpty()
// simple match
input.matches("\\S")
// match with precompiled pattern
final Pattern PATTERN = Pattern.compile("\\S");
PATTERN.matcher(input).matches()
// java 11's isBlank
input.isBlank()
each 10.000.000 times.
The results:
METHOD min max note
trim: 18 313 much slower if text not trimmed
match: 1799 2010
pattern: 571 662
isBlank: 60 338 faster the earlier hits the first non-whitespace character
Quite surprisingly the trim+empty is the fastest. Even if it needs to construct the trimmed text. Still faster then simple for-loop looking for one single non-whitespaced character...
EDIT:
The longer text, the more numbers differs. Trim of long text takes longer time than just simple loop. However, the regexs are still the slowest solution.
With Java-11+, you can make use of the String.isBlank API to check if the given string is not all made up of whitespace -
String str1 = " ";
System.out.println(str1.isBlank()); // made up of all whitespaces, prints true
String str2 = " a";
System.out.println(str2.isBlank()); // prints false
The javadoc for the same is :
/**
* Returns {#code true} if the string is empty or contains only
* {#link Character#isWhitespace(int) white space} codepoints,
* otherwise {#code false}.
*
* #return {#code true} if the string is empty or contains only
* {#link Character#isWhitespace(int) white space} codepoints,
* otherwise {#code false}
*
* #since 11
*/
public boolean isBlank()
The trim method should work great for you.
http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/java/lang/String.html#trim()
Returns a copy of the string, with
leading and trailing whitespace
omitted. If this String object
represents an empty character
sequence, or the first and last
characters of character sequence
represented by this String object both
have codes greater than '\u0020' (the
space character), then a reference to
this String object is returned.
Otherwise, if there is no character
with a code greater than '\u0020' in
the string, then a new String object
representing an empty string is
created and returned.
Otherwise, let k be the index of the
first character in the string whose
code is greater than '\u0020', and let
m be the index of the last character
in the string whose code is greater
than '\u0020'. A new String object is
created, representing the substring of
this string that begins with the
character at index k and ends with the
character at index m-that is, the
result of this.substring(k, m+1).
This method may be used to trim
whitespace from the beginning and end
of a string; in fact, it trims all
ASCII control characters as well.
Returns: A copy of this string with
leading and trailing white space
removed, or this string if it has no
leading or trailing white space.leading or trailing white space.
You could trim and then compare to an empty string or possibly check the length for 0.
Alternative:
boolean isWhiteSpaces( String s ) {
return s != null && s.matches("\\s+");
}
trim() and other mentioned regular expression do not work for all types of whitespaces
i.e: Unicode Character 'LINE SEPARATOR' http://www.fileformat.info/info/unicode/char/2028/index.htm
Java functions Character.isWhitespace() covers all situations.
That is why already mentioned solution
StringUtils.isWhitespace( String ) /or StringUtils.isBlank(String)
should be used.
StringUtils.isEmptyOrWhitespaceOnly(<your string>)
will check :
- is it null
- is it only space
- is it empty string ""
https://www.programcreek.com/java-api-examples/?class=com.mysql.jdbc.StringUtils&method=isEmptyOrWhitespaceOnly
While personally I would be preferring !str.isBlank(), as others already suggested (or str -> !str.isBlank() as a Predicate), a more modern and efficient version of the str.trim() approach mentioned above, would be using str.strip() - considering nulls as "whitespace":
if (str != null && str.strip().length() > 0) {...}
For example as Predicate, for use with streams, e. g. in a unit test:
#Test
public void anyNonEmptyStrippedTest() {
String[] strings = null;
Predicate<String> isNonEmptyStripped = str -> str != null && str.strip().length() > 0;
assertTrue(Optional.ofNullable(strings).map(arr -> Stream.of(arr).noneMatch(isNonEmptyStripped)).orElse(true));
strings = new String[] { null, "", " ", "\\n", "\\t", "\\r" };
assertTrue(Optional.ofNullable(strings).map(arr -> Stream.of(arr).anyMatch(isNonEmptyStripped)).orElse(true));
strings = new String[] { null, "", " ", "\\n", "\\t", "\\r", "test" };
}
public static boolean isStringBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}

Categories

Resources