Win a copy of Zero to AI - A non-technical, hype-free guide to prospering in the AI era this week in the Artificial Intelligence and Machine Learning forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Paul Clapham
  • Bear Bibeault
  • Jeanne Boyarsky
Sheriffs:
  • Ron McLeod
  • Tim Cooke
  • Devaka Cooray
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Jj Roberts
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • salvin francis
  • Scott Selikoff
  • fred rosenberger

String question

 
Greenhorn
Posts: 26
Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
String s1 = "abc";
String s2 = " abc".stripLeading();

System.out.println(s1);
System.out.println(s2);

System.out.println(s1 == s2);


This prints out

abc
abc
false


I was expecting that when it strips leading , its going to return the same string as s1 since that is already in the pool. Why did the last statement return false ?
 
Bartender
Posts: 3655
38
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can check source code of java.lang.String -- freely available.

The method internally creates a new string every time (unless it's null or blank)





Again, I encourage you to look at sources, a lot of useful stuff there 8)
 
Marshal
Posts: 70629
288
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Mikalai Zaikin wrote:. . . source code of java.lang.String . . . I encourage you to look at sources, a lot of useful stuff there 8)

Yes, source code can be useful, but you need to read it carefully. There isn't a static method like that in the API, only this instance no‑args method. It would surprise me rather to see a public static String stripLeading(byte[]) method. Surely that method would have private access?
To answer the actual question:- look at the JLS (=Java® Language Specification) for the definiton of compile‑time constants (officially called, “constant expressions”). You will see that method calls are not permitted in any of the expressions. It tells you that...

Constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern.

But the second instance of "abc" isn't a constant expression, being created via a method call, its actual value is only known at runtime, and it isn't put into the String pool. If you want that == te‍st to return true, try changing the second line to read,
 
Mikalai Zaikin
Bartender
Posts: 3655
38
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:It would surprise me rather to see a public static String stripLeading(byte[]) method. Surely that method would have private access?



I provided 2 separate code snippets and the reason is that they belong to different classes: yo can see that String instance method invokes static methods on StringXXX utility classes.
 
Campbell Ritchie
Marshal
Posts: 70629
288
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry.
 
Namith Kumar
Greenhorn
Posts: 26
Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for your explanation Mikalai Zaikin and Campbell Ritchie. Makes sense now . I should start getting into the habit of checking API references and Source code .
 
Master Rancher
Posts: 4700
49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:
To answer the actual question:- look at the JLS (=Java® Language Specification) for the definiton of compile‑time constants (officially called, “constant expressions”). You will see that method calls are not permitted in any of the expressions. It tells you that...

Constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern.

But the second instance of "abc" isn't a constant expression, being created via a method call, its actual value is only known at runtime, and it isn't put into the String pool. If you want that == te‍st to return true, try changing the second line to read,



I'm not sure this is actually relevant.
There's no reason at all that the stripLeading method couldn't return the original String if there are no leading spaces.
It's a case of "implementation detail" as to whether you get the original String back or a new one.



And, of course, even if it did it this way you shouldn't be relying on that (unless it's documented as such) because (being an implementation detail) it could change between versions.
 
Campbell Ritchie
Marshal
Posts: 70629
288
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Dave Tolls wrote:. . . There's no reason at all that the stripLeading method couldn't return the original String if there are no leading spaces. . . .

No, there isn't, and the stripLeading() method's documentation doesn't say whether it does or doesn't. A little experiment on JShell suggests however that the behaviour you suggest does actually occur, but as you said that behaviour can change from version to version:-

jshell
String s0 =|  Welcome to JShell -- Version 12
|  For an introduction type: /help intro

jshell> String s0 = "Campbell";
s0 ==> "Campbell"

jshell> String s1 = "Campbell";
s1 ==> "Campbell"

jshell> String s2 = " Campbell".stripLeading();
s2 ==> "Campbell"

jshell> s1 == s2
$4 ==> false

jshell> s0 == s1
$5 ==> true

jshell> s0 == "Campbell".stripLeading()
$6 ==> true

In OP's question however a space was removed and a different object was returned.
 
Sheriff
Posts: 15930
265
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Namith Kumar wrote:I was expecting that when it strips leading , its going to return the same string as s1 since that is already in the pool. Why did the last statement return false ?


The String pool is an internal mechanism used to improve performance and while knowing how it works is useful, you shouldn't assume anything like that or rely on behavior based on it. There's no "String Pool API" (edit: aside from intern()) so that should be a big clue that it's not meant for public consumption.

I think it was already pointed out that while "abc" is a literal String value that the compiler will put in the String pool, the same can't be said for " abc".stripLeading() because that's a method call expression and thus will be seen as a "dynamic" value that can only be determined at runtime, not a "static" value that can be determined at compile time. The compiler will never execute code so it has no way of determining that " abc".stripLeading() will actually only ever evaluate to the same "abc" value every time. You'll understand this more if/when you study how compilers work.

The key to understanding the behavior you're seeing, in my opinion, is NOT by looking at the source code of the method in question. Rather, it's understanding when the compiler can determine if a String value can be pooled or not.

"abc" can be pooled by the compiler
" abc".stripLeading() can't be pooled by the compiler
 
Dave Tolls
Master Rancher
Posts: 4700
49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:In OP's question however a space was removed and a different object was returned.



Ah.
My eyes completely missed that there was a space at the start of the second string!
I thought they were both the same...

Hopefully I haven't confused things!
 
Campbell Ritchie
Marshal
Posts: 70629
288
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Dave Tolls wrote:. . . missed . . . a space . . . Hopefully I haven't confused things!

No, I don't think you have confused things.
 
Saloon Keeper
Posts: 12422
269
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
All this goes to show that you really shouldn't compare strings using the equals operator ever.
 
Campbell Ritchie
Marshal
Posts: 70629
288
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:. . . you really shouldn't compare strings using the equals operator ever.

Except in cert exams That is why this sort of question comes up at all.
 
Junilu Lacar
Sheriff
Posts: 15930
265
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell wrote:Except in cert exams  


I know you're saying that tongue-in-cheek but the point of having that kind of example in cert exams is not to promote or even suggest its use in regular programming but rather to determine whether or not the exam taker understands that == checks for reference equality. I wish certification study guides would call this out more explicitly though because it seems like it would be easy for people who don't know any better to mistakenly think that using == to compare object references instead of equals() is good practice just because it's being shown in a certification guide.
 
Namith Kumar
Greenhorn
Posts: 26
Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think the mistake i made was assuming that since i did not use any "new" in my code to create a new string object, it would look for stuff in the string pool and use that if available. So that's where looking at that code helped . When i saw that internally it ended up ultimately creating a new string , i understand why the == would return false.
 
Junilu Lacar
Sheriff
Posts: 15930
265
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Namith Kumar wrote:I think the mistake i made was assuming that since i did not use any "new" in my code to create a new string object, it would look for stuff in the string pool and use that if available. So that's where looking at that code helped . When i saw that internally it ended up ultimately creating a new string , i understand why the == would return false.



I don't think this is useful way to understand the workings of == in this case. Are you then going to have to dig into the internals of all methods that return a String to understand what the outcome might be? Do you actually understand the difference between using == vs equals()? What if stripLeading() were implemented differently?

The reason == will definitively return false in the example is because the compiler sees " abc".stripLeading() as a dynamic value, not a static one. How stripLeading() is implemented is irrelevant.  On the other hand, the result of "abc" == "abc".stripLeading() does depend on how stripLeading() is implemented. Do you understand why?

Just for the sake argument, answer this question: If you knew nothing about the implementation of someStringMethod(), could you definitively say whether "abc" == "abc".someStringMethod() is going to be true?
 
Campbell Ritchie
Marshal
Posts: 70629
288
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Namith Kumar wrote:. . . assuming that . . .

Beware of assuming anything; if it doesn't say it in the documentation or specification, it doesn't (officially) exist.
 
Junilu Lacar
Sheriff
Posts: 15930
265
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:The reason == will definitively return false in the example is because the compiler sees " abc".stripLeading() as a dynamic value, not a static one.


On second thought, allow me to rephrase this because the part about "the compiler sees it" is misleading at best.

"abc" == " abc".stripLeading() will 100% be false because:
1. " abc" and "abc" are two different String literals (and will be pooled separately) -- Edit: the fact that they're pooled separately isn't even relevant
2. " abc".stripLeading() is a method invocation expression, so there's no way that the compiler will evaluate it and pool the resulting value.
3. Given that the result of " abc".stripLeading() is "abc" and that there is no way to dynamically grab a reference to the "abc" literal that's in the String pool, the returned "abc" is definitely going to be a dynamically created String.

EDIT - I apologize for the number of edits; I really should have experimented first before spouting off the above. Let me correct myself once again, and hopefully this will be the last time in this thread.

1. Whether or not "abc" == " abc".stripLeading() returns true or false actually does depend on the implementation of stripLeading().  If it were implemented this way, then the expression would be true:

Obviously, it's not actually implemented this way.

Predict what the output of this code will be:

(You can run it here: https://repl.it/@jlacar/StringReferenceEqualityExample)

2. That said, the String constant pool is an internal mechanism meant to help improve performance. From an API usage perspective, you shouldn't rely on its use or assume that it will be used by a method that returns String values.

3. As Stephan said before: never use == to check if two Strings represent the same sequence of characters. Use equals() instead.
 
Campbell Ritchie
Marshal
Posts: 70629
288
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:. . . I apologize . . .

But you got a helpful post in the end.

Is it better to look on it as the compiler seeing the result of a method call as “dynamic”, or the compiler not seeing that result at all?

stripLeading() [...is...] not actually implemented this way. . . . .

It would never occur to me to implement it that way, if anybody asked me to. That method isn't doing one thing any more but two things: it is stripping whitespace and interning the result. I would have to call it stripLeadingAndIntern(). And we all know what a bad idea it is to have a method with ...And... in its name.
 
Junilu Lacar
Sheriff
Posts: 15930
265
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Is it better to look on it as the compiler seeing the result of a method call as “dynamic”, or the compiler not seeing that result at all?


That's kind of why I backpedalled on that -- I don't think it's even relevant given that the result really depends on the implementation of stripLeading(). It's a good thing that String methods like this behave fairly consistently and, arguably, unsurprisingly. That is, I'm not aware of any methods that call intern() if the result is different from the original String value just in case there was already one like it in the String constant pool.

In general, it seems to me the design approach for the String methods is this: If the result is the same as this string (essentially, nothing needs to be done), then return a reference to this string. Otherwise, return a new String after performing the operation. That approach makes sense to me when you consider that Strings are a fundamental and ubiquitous type that sees a lot of use and deciding to "optimize" by calling intern() all the time might be counterproductive in many cases. You know, premature optimization and all that kind of evil.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic