Reputation: 987
In this code, Each time i am calling goodMethod(), it is going to use the unique object created in the Heap Space with static word.
MY QUESTION is : when i am calling badMethod(), is it going to create a new String object in the Heap Space each time i am calling this method ? So if i am calling my method 1_200_000 time, is it going to create 1_200_000 string object in the heap Space ?
There is no doubt that the first method is better (for readability and maintainability of code). I am only asking here about number of object created in memory
Thanks
I have read a lot about this on google but didn't find an response with argument or proof. Please also if you know how i can test this, thanks to share.
public class Main {
private static final String HELLO = "hello";
private static final String WORLD = "world";
public static void main(String[] args) {
for (int i = 0; i < 1_200_000; i++) {
goodMethod();
badMethod();
}
}
private static void goodMethod(){
System.out.println(HELLO);
System.out.println(WORLD);
}
private static void badMethod(){
System.out.println("hello");
System.out.println("world");
}
}
// an other example
Map<String, Object> map = new HashMap<>();
map.put("myKey", xxx.getYYY());
// somewhere else
map.put("myKey", zzz.getYYY());
// instead of :
private static final String MY_KEY = "myKey"
map.put(MY_KEY, xxx.getYYY());
map.put(MY_KEY, zzz.getYYY());
EDIT : I am not asking about concatenation, i have remove the concatenation from the sample code
Upvotes: 3
Views: 2566
Reputation: 298469
For the code example
public class Main {
private static final String HELLO = "hello";
private static final String WORLD = "world";
private static void goodMethod(){
System.out.println(HELLO);
System.out.println(WORLD);
}
private static void badMethod(){
System.out.println("hello");
System.out.println("world");
}
}
There is no difference between goodMethod()
and badMethod()
at all.
The key point is that not only "hello"
and "world"
are compile-time constants, but HELLO
and WORLD
are as well.
As The Java® Language Specification puts it:
A constant variable is a
final
variable of primitive type or typeString
that is initialized with a constant expression (§15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1), reachability (§14.21), and definite assignment (§16.1.1).
And in §13.1:
A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.
If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field.
In other words, the field references to HELLO
and WORLD
get resolved at compile time and replaced with their constant values, just like if you had written these values in the first place.
You can verify this by looking at the bytecode using, e.g. javap -p -c Main
:
Compiled from "Main.java"
public class Main {
private static final java.lang.String HELLO;
private static final java.lang.String WORLD;
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
private static void goodMethod();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #6 // String world
13: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: return
private static void badMethod();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #6 // String world
13: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: return
}
You don’t need to understand bytecode in all details to see that the compiled code of both methods, goodMethod()
and badMethod()
is identical. Of course, identical code can not have performance differences related to the way it was created.
The same applies to your second example, there is no difference between using a string literal or a constant variable.
Regarding the coding style, I agree with Peter Lawrey’s answer. Using a constant variable does not improve the code when its name does not provide additional meaning. Without such meaning, the actual value says more than the variable name. See also this answer.
Upvotes: 7
Reputation: 533750
There is no doubt that the first method is better (for readability and maintainability of code). I am only asking here about number of object created in memory
I would argue the first example is less readable, and less maintainable, but it is the same at runtime, and no faster or slower.
System.out.println("hello");
You know exactly what it will print without having to look around the class.
In the first case, you don't really know what it is going to print unless you check.
private static final String HELLO = "hello";
private static final String HELLO = "Hello";
private static final String HELLO = "HELLO";
private static final String HELLO = "G'Day";
i.e. it's less readable, because you have to look into two different places in the class to know what the line of code does.
NOTES:
System.out
but this doesn't matter in comparison toan other example
Map<String, Object> map = new HashMap<>();
map.put("myKey", xxx.getYYY());
// somewhere else
map.put("myKey", zzz.getYYY());
// instead of :
private static final String MY_KEY = "myKey"
map.put(MY_KEY, xxx.getYYY());
map.put(MY_KEY, zzz.getYYY());
Neither example creates any Strings, but every put
creates a new Map.Entry object.
Upvotes: 1
Reputation: 1
goodMethod implementation refer to string pool. badMethod implementation refer to object . when we are passing string directly as println menthod its refered as object.
Upvotes: 0
Reputation: 7998
Both examples are equal and works with three objects in memory ("hello", "world", "helloworld"). Concatenation of two literals is compile time expression. You can test this simply:
// test one object used for constants
String stringOne = "constant";
String stringTwo = "constant";
assertThat(stringOne)
.isSameAs(stringTwo);
// test one object is used for string literals concatenation
stringOne = "constant2";
stringTwo = "constant" + "2";
assertThat(stringOne)
.isSameAs(stringTwo);
Similar question on string contatenation
Upvotes: 0
Reputation: 824
Actually I think jvm is not so stupid. At this stage it can check that you already have "hello"
as a string and not create it again. Just reuse it. The problem is when you create unique strings or string with constructor: new String("hello")
. Then every time a new space is taken.
P.S. you also create a unique string by concatenating with +
. Now in your example System.out.println("hello" + "world");
will try to create if does not already exist "hello"
, "world"
and "helloworld"
strings.
Upvotes: 0
Reputation: 952
Java has string pool that stores Strings. If you use string that is already there - no new string is created. What happenes when you alter string then? why it does not alter all uses of that string? causes String is immutable - that means that once created in memory it will never be changed - can be only deleted.
when you work on strings, for example:
String TEST = "test";
test += "copy paste";
string test is not altered in memory, just new string is created in string pool (or is already there) and variable TEST from now on will point to new (or from heap) string. The old one - "test" will still be there until GC does his work.
try this article - https://www.baeldung.com/java-string-pool it is fairly simple concept
Upvotes: 0
Reputation: 147154
Concatenating compile-time constant String
s results in a compile-time constant String
. So it does not matter - the concatenation does not happen at runtime.
If the String
s weren't compile-time constants then you would always need a new object (other than, perhaps, in trivial cases).
Upvotes: 1