Reference is not created while using + operator to concat two strings - java

I am trying to concatenate two strings, one string with some value and another with empty.
Example:
String string1="Great"
String string2="";
and concatenating these two string with concat function and + operator
Example:
String cat=string1.concat(string2)
String operator=string1+string2
As per my understanding, while using empty string in concat function as the string2 is empty no new reference will be created. But while using + operator a new reference will be created in the string pool constant. But in the below code while using the + operator new reference is not created.
public class Main {
public static void main(String[] args) {
String string1="Great",string2="";
String cat=string1.concat(string2);
if(string1==cat)
{
System.out.println("Same");
}
else
{
System.out.println("Not same");
}
String operator=string1+string2;
if(operator==string1)
System.out.println("Same");
else
System.out.println("Not same");
}
}
Output:
string 1 :69066349
cat :69066349
Same
string1 :69066349
operator :69066349
Not same
From the above code, as it's using + operator, the reference for the variable : operator should refer to the new memory, but it's pointing to the string1 reference. Please explain the above code.

It is all in the documentation.
For String.concat, the javadoc states this:
If the length of the argument string is 0, then this String object is returned.
For the + operator, JLS 15.8.1 states:
The result of string concatenation is a reference to a String object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string.
The String object is newly created (§12.5) unless the expression is a constant expression (§15.29).
As you can see, the results will be different for the case where the 2nd string has length zero and this is not a constant expression.
That is what happens in your example.
You also said:
But while using + operator a new reference will be created in the string pool constant.
This is not directly relevant to your question, but ... actually, no it won't be created there. It will create a reference to a regular (not interned) String object in the heap. (It would only be in the class file's constant pool ... and hence the string pool ... if it was a constant expression; see JLS 15.29)
Note that the string pool and the classfile constant pool are different things.
Can I add a couple of things:
You probably shouldn't be using String.concat. The + operator is more concise, and the JIT compiler should know how to optimize away the creation of unnecessary intermediate strings ... in the few cases where you might consider using concat for performance reasons.
It is a bad idea to exploit the fact that no new object is created so that you can use == rather than equals(Object). Your code will be fragile. Just use equals always for comparing String and the primitive wrapper types. It is simpler and safer.
In short, the fact that you are even asking this question suggests that you are going down a blind alley. Knowledge of this edge-case difference between concat and + is ... pointless ... unless you are planning to enter a quiz show for Java geeks.

Related

string constant pool using + operator

public class Strings
{
public static void main(String ads[])
{
String a = "meow";
String ab = a + "deal";
String abc= "meowdeal";
System.out.println (ab==abc);
}
}
why output is false?
In this program ab is created in string literal and then abc created but why ab and abc not refer to the same memory in string constant pool ,because before creating abc it search in string constant pool for String meowdeal.
Java only pools strings it knows about at compile time; string constants and constant string expressions. a is a local variable, so a + "deal" is a string expression that isn't evaluated until runtime (even though you looking at it can see that it should be constant). The Java compiler doesn't know it's a constant expression, and doesn't put it in the pool. It performs the string concatenation at runtime, resulting in a different object than any in the pool.
I'll explain what's happening:
public class Strings {
public static void main(String ads[]) {
String a = "meow"; // new string created
String ab = a + "deal"; // again a new string created. Reference different.
String abc = "meowdeal"; // a whole new string.
System.out.println(ab == abc);// even though the values are same, reference is different. For value equality, use .equals()
}
}
Your question implies that you expect Java to check the result of every string concatenation to see if there is a matching string in the string constant pool - but this would be grossly inefficient. String concats are always new objects unless all the strings are compile-time constants.
If you really want to compare the strings using == you need to intern the constructed string like so:
ab=(a+"deal").intern();
However this would be for a very specific use case and very uncommon.
Note that this is a different case from when two constants are concatenated; given "ab"+"cd" the compiler is required to resolve the expression to "abcd" and pool the result. The same would be true if one or both of the values are compile-time constants, static final ....

Java string references different with new, same without new

Having never worked with Java much before, I was teaching myself generics syntax. I was testing out the simple generic function with some strings, and noticed something a little strange:
public class Main {
public static <T> boolean areSameReference(T lhs, T rhs) {
return lhs == rhs;
}
public static void main(String[] args) {
String s = new String("test1");
String t = s;
String u = new String("test1");
System.out.println(areSameReference(s, t)); //true
System.out.println(areSameReference(s, u)); //false
String v = "test2";
String w = "test2";
System.out.println(areSameReference(v, w)); //true
}
}
How come [s] and [u] are different references, but [v] and [w] are the same reference? I would have thought that with or without "new" the string literal would have caused them to be the same or different consistently in both cases.
Am I missing something else going on here?
How come [s] and [u] are different references,
Because you told the compiler you wanted new strings, didn't you?
As per JLS 3.10.5
a string literal always refers to the same instance of class String.
This is because string literals - or, more generally, strings that are
the values of constant expressions (§15.28) - are "interned" so as to
share unique instances, using the method String.intern.
String v = "test2";
    String w = "test2";
Will be considered as String literals.
When you use new operator to construct a String object it allocates new String object.
With new, you invoke the memory management system and get a new object.
Without new, the compiler optimizes the string contents into one entry in the '.class' constant table, resulting in two accesses to the same entry in the '.class' constant table.
The = comparison operator in Java is a reference comparison operation, so you will see differences between the two techniques. You might be able to hide those differences with enough use of String.intern(otherString).
The lesson to take home here is that except in extreme circumstances, always use .equals(...) to compare to objects.
The JVM keeps a pool of strings so that it doesn't waste memory with duplicate strings. Therefore, v and w should be the same. I'm guessing that the behavior that you're experiencing is due to the contract implied in the new String(String original) constructor, which indicates that it creates a new object (see http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#String(java.lang.String)).
String objects are immutable, where string references are mutable. When you define "s" and "u", new objects for each are created. Value here does not matter because you invoke constructor, but when you assign same value to different String objects, they become references to same "test2" object in memory.
I would recommend reading more about immutable objects in Java, a good article is here:
http://javarevisited.blogspot.com/2010/10/why-string-is-immutable-in-java.html

Comparing two identical strings with == returns false [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am making an archive for my family. There are no syntax errors, however whenever I type in "Maaz", it evaluates realName == "Maaz" to false and goes to the else statement.
import java.util.Scanner;
public class MainFamily {
public static void main (String [] args) {
System.out.println("Enter you're name here");
Scanner name = new Scanner(System.in);//Scanner variable = name
String realName;
realName = name.nextLine();//String variable = user input
System.out.println("Name: "+ realName);
if (realName == "Maaz") {
System.out.println("Name: Maaz");
} else {
System.out.println("This person is not in the database");
}
}
}
TL;DR
You wrote (this doesn't work):
realName == "Maaz"
You meant this:
realname.equals("Maaz")
or this:
realname.equalsIgnoreCase("Maaz")
Explanation
In Java (and many other Object-Oriented programming languages), an object is not the same as a data-type. Data-types are recognized by the runtime as a data-type.
Examples of data-types include: int, float, short.
There are no methods or properties associated with a data-type. For example, this would throw an error, because data-types aren't objects:
int x = 5;
int y = 5;
if (x.equals(y)) {
System.out.println("Equal");
}
A reference is basically a chunk of memory that explicitly tells the runtime environment what that data-block is. The runtime doesn't know how to interpret this; it assumes that the programmer does.
For example, if we used Integer instead of int in the previous example, this would work:
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x.equals(y)) {
System.out.println("Equal");
}
Whereas this would not give the expected result (the if condition would evaluate to false):
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x == y) {
System.out.println("Equal");
}
This is because the two Integer objects have the same value, but they are not the same object. The double equals basically checks to see if the two Objects are the same reference (which has its uses).
In your code, you are comparing an Object with a String literal (also an object), which is not the same as comparing the values of both.
Let's look at another example:
String s = "Some string";
if (s == "Some string") {
System.out.println("Equal");
}
In this instance, the if block will probably evaluate to true. Why is this?
The compiler is optimized to use as little extra memory as is reasonable, although what that means depends on the implementation (and possibly runtime environment).
The String literal, "Some string", in the first line will probably be recognized as equivalent to the String literal in the second line, and will use the same place in memory for each. In simple terms, it will create a String object and plug it into both instances of "Some string". This cannot be relied upon, so using String.equals is always a better method of checking equivalence if you're only concerned with the values.
do this instead
if (realName.equals("Maaz"))
equals() should be used on all non-primitive objects, such as String in this case
'==' should only be used when doing primitive comparisons, such as int and long
use
if(realName.equals("Maaz"))
use == with primitive data type like int boolean .... etc
but if you want to compare object in java you should use the equals method
You have to compare objects with realName.equals ("Maaze"), not with ==.
It is best practice to compare Strings using str.equals(str2) and not str == str2. As you observed, the second form doesn't work a lot of the time. By contrast, the first form always works.
The only cases where the == approach will always work are when the strings are being compared are:
string literals or references to string literals, or
strings that have been "interned" by application-level code calling str = str.intern();.
(And no, strings are not interned by default.)
Since it is generally tricky to write programs that guarantee these preconditions for all strings, it is best practice to use equals unless there is a performance-related imperative to intern your strings and use ==.
Before that you decide that interning is a good idea, you need to compare the benefits of interning with the costs. Those costs include the cost of looking up the string in the string pool's hash table and the space and GC overheads of maintaining the string pool. These are non-trivial compared with the typical costs of just using a regular string and comparing using equals.
You can also use
realname.equalsIgnoreCase("Maaz")
This way you can accept Maaz, maaz, maaZ, mAaZ, etc.
== tests shallow equality. It checks if two objects reference the same location in memory.
Intriguing. Although, as others have stated, the correct way is to use the .equals(...) method, I always thought strings were pooled (irrespective of their creation). It seems this is only true of string literals.
final String str1 = new String("Maaz");
final String str2 = new String("Maaz");
System.out.println(str1 == str2); // Prints false
final String str3 = "Laaz";
final String str4 = "Laaz";
System.out.println(str3 == str4); // Prints true
Since you are working on strings, you should use equals to equalsIngnorecase method of String class. "==" will only compare if the both objects points to same memory location, in your case, both object are different and will not be equal as they dont point to same location. On the other hand, equals method of String class perform a comparison on the basis of the value which objects contains. Hence, if you will use equals method, your if condition will be satisfied.
== compares object references or primitive types (int, char, float ...)
equals(), you can override this method to compare how both objects are equal.
for String class, its method equal() will compare the content inside if they are the same or not.
If your examples, both strings do not have the same object references, so they return false, == are not comparing the characters on both Strings.
It seems nobody yet pointed out that the best practice for comparing an object with a constant in Java is calling the equals method of the constant, not the variable object:
if ("Maaz".equals (realName)) {}
This way you don't need to additionally check if the variable realName is null.
if(realName.compareTo("Maaz") == 0) {
// I dont think theres a better way do to do this.
}

Concatenating null strings in Java [duplicate]

This question already has answers here:
String concatenation with Null
(3 answers)
Closed 3 years ago.
Why does the following work? I would expect a NullPointerException to be thrown.
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Why must it work?
The JLS 5, Section 15.18.1.1 JLS 8 § 15.18.1 "String Concatenation Operator +", leading to JLS 8, § 5.1.11 "String Conversion", requires this operation to succeed without failure:
...Now only reference values need to be considered. If the reference is null, it is converted to the string "null" (four ASCII characters n, u, l, l). Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null, then the string "null" is used instead.
How does it work?
Let's look at the bytecode! The compiler takes your code:
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
and compiles it into bytecode as if you had instead written this:
String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"
(You can do so yourself by using javap -c)
The append methods of StringBuilder all handle null just fine. In this case because null is the first argument, String.valueOf() is invoked instead since StringBuilder does not have a constructor that takes any arbitrary reference type.
If you were to have done s = "hello" + s instead, the equivalent code would be:
s = new StringBuilder("hello").append(s).toString();
where in this case the append method takes the null and then delegates it to String.valueOf().
Note: String concatenation is actually one of the rare places where the compiler gets to decide which optimization(s) to perform. As such, the "exact equivalent" code may differ from compiler to compiler. This optimization is allowed by JLS, Section 15.18.1.2:
To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
The compiler I used to determine the "equivalent code" above was Eclipse's compiler, ecj.
See section 5.4 and 15.18 of the Java Language specification:
String conversion applies only to the
operands of the binary + operator when
one of the arguments is a String. In
this single special case, the other
argument to the + is converted to a
String, and a new String which is the
concatenation of the two strings is
the result of the +. String conversion
is specified in detail within the
description of the string
concatenation + operator.
and
If only one operand expression is of
type String, then string conversion is
performed on the other operand to
produce a string at run time. The
result is a reference to a String
object (newly created, unless the
expression is a compile-time constant
expression (§15.28))that is the
concatenation of the two operand
strings. The characters of the
left-hand operand precede the
characters of the right-hand operand
in the newly created string. If an
operand of type String is null, then
the string "null" is used instead of
that operand.
The second line is transformed to the following code:
s = (new StringBuilder()).append((String)null).append("hello").toString();
The append methods can handle null arguments.
You are not using the "null" and therefore you don't get the exception. If you want the NullPointer, just do
String s = null;
s = s.toString() + "hello";
And I think what you want to do is:
String s = "";
s = s + "hello";
This is behavior specified in the Java API's String.valueOf(Object) method. When you do concatenation, valueOf is used to get the String representation. There is a special case if the Object is null, in which case the string "null" is used.
public static String valueOf(Object obj)
Returns the string representation of the Object argument.
Parameters:
obj - an Object.
Returns:
if the argument is null, then a string equal to "null"; otherwise, the value of obj.toString() is returned.

Java == for String objects ceased to work?

public class Comparison {
public static void main(String[] args) {
String s = "prova";
String s2 = "prova";
System.out.println(s == s2);
System.out.println(s.equals(s2));
}
}
outputs:
true
true
on my machine. Why? Shouldn't be == compare object references equality?
Because String instances are immutable, the Java language is able to make some optimizations whereby String literals (or more generally, String whose values are compile time constants) are interned and actually refer to the same (i.e. ==) object.
JLS 3.10.5 String Literals
Each string literal is a reference to an instance of class String. String objects have a constant value. String literals-or, more generally, strings that are the values of constant expressions -are "interned" so as to share unique instances, using the method String.intern.
This is why you get the following:
System.out.println("yes" == "yes"); // true
System.out.println(99 + "bottles" == "99bottles"); // true
System.out.println("7" + "11" == "" + '7' + '1' + (char) (50-1)); // true
System.out.println("trueLove" == (true + "Love")); // true
System.out.println("MGD64" == "MGD" + Long.SIZE);
That said it needs to be said that you should NOT rely on == for String comparison in general, and should use equals for non-null instanceof String. In particular, do not be tempted to intern() all your String just so you can use == without knowing how string interning works.
Related questions
Java String.equals versus ==
difference between string object and string literal
what is the advantage of string object as compared to string literal
Is it good practice to use java.lang.String.intern()?
On new String(...)
If for some peculiar reason you need to create two String objects (which are thus not == by definition), and yet be equals, then you can, among other things, use this constructor:
public String(String original) : Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
Thus, you can have:
System.out.println("x" == new String("x")); // false
The new operator always create a new object, thus the above is guaranteed to print false. That said, this is not generally something that you actually need to do. Whenever possible, you should just use string literals instead of explicitly creating a new String for it.
Related questions
Java Strings: “String s = new String(”silly“);”
What is the purpose of the expression “new String(…)” in Java?
JLS, 3.10.5 => It is guaranteed that a literal string object will be reused by any other code running in the same virtual machine that happens to contain the same string literal
If you explicitly create new objects, == returns false:
String s1 = new String("prova");
String s2 = new String("prova");
System.out.println(s1 == s2); // returns false.
Otherwise the JVM can use the same object, hence s1 == s2 will return true.
It does. But String literals are pooled, so "prova" returns the same instance.
String s = "prova";
String s2 = "prova";
s and s2 are literal strings which are pointing the same object in String Pool of JVM, so that the comparison returns true.
Yes, "prova" is stored in the java inner string pool, so its the same reference.
Source code literals are part of a constant pool, so if the same literal appears multiple times, it will be the same object at runtime.
The JVM may optimize the String usage so that there is only one instance of the "equal" String in memory. In this case also the == operator will return true. But don't count on it, though.
You must understand that "==" compares references and "equals" compares values. Both s and s1 are pointing to the same string literal, so their references are the same.
When you put a literal string in java code, the string is automatically interned by the compiler, that is one static global instance of it is created. Or more specifically, it is put into a table of interned strings. Any other quoted string that is exactly the same, content-wise, will reference the same interned string.
So in your code s and s2 are the same string
Ideally it should not happen ever. Because java specification guarantees this. So I think it may be the bug in JVM, you should report to the sun microsystems.

Categories