mourad m
mourad m

Reputation: 987

Java performance : private static final String vs local String ? number of object created in Heap Space

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

Answers (7)

Holger
Holger

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 type String 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

Peter Lawrey
Peter Lawrey

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:

  • neither method creates any objects.
  • even if they did it would matter compared with the cost of
  • every time you print you obtain a lock on the System.out but this doesn't matter in comparison to
  • the cost of writing to the screen is thousands of times more expensive than creating objects.

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());

Neither example creates any Strings, but every put creates a new Map.Entry object.

Upvotes: 1

sant prajapati
sant prajapati

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

udalmik
udalmik

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

Level_Up
Level_Up

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

Lukas Novicky
Lukas Novicky

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

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

Concatenating compile-time constant Strings results in a compile-time constant String. So it does not matter - the concatenation does not happen at runtime.

If the Strings weren't compile-time constants then you would always need a new object (other than, perhaps, in trivial cases).

Upvotes: 1

Related Questions