Strings in java 8 less memory

I got the code below, and I was asked which option gets the following template:

XXXXXXXXXXXXX-2324

...

Code below:

public class CCMark { public static String maskCC(String creditCard){ String x = "XXXX-XXXX-XXXX-"; //line 1 } public static void main(String[] args) { System.out.println(maskCC("1234-5678-1234-2324")); System.out.println(maskCC("4567-5678-1234-5643")); System.out.println(maskCC("1234-5678-1234-4654")); System.out.println(maskCC("4567-5678-1234-5435")); } } 

Below are the possible parameters that can be inserted into the string "1":

  A) return x + creditCard.substring(15, 19); B) StringBuilder sb = new StringBuilder(x); sb.append(creditCard, 15, 19); return sb.toString(); 

I think the best option is here, since A and B give us the same result, this is B because it uses StringBuilder, which means its approach is volatile, so it will use less memory than option A.

Am I really wrong? Is option A the best option for this particular situation?

+5
source share
2 answers

Parameters a and b are identical because the Java compiler converts the option to option b. You can move the declaration of x outside the method (and make it final ). Sort of,

 static final String x = "XXXX-XXXX-XXXX-"; public static String maskCC(final String creditCard) { return x + creditCard.substring(15, 19); } 

Using javap to check the first versus the second. Java code for example

 String x = "XXXX-XXXX-XXXX-"; String creditCard = "1234-5678-1234-23324"; String x2 = x + creditCard.substring(15, 19); StringBuilder sb = new StringBuilder(x); sb.append(creditCard, 15, 19); String x3 = sb.toString(); 

generates a bytecode that looks like ( note lines 6-31 and 32-58)

  0: ldc #16 // String XXXX-XXXX-XXXX- 2: astore_1 3: ldc #18 // String 1234-5678-1234-23324 5: astore_2 6: new #20 // class java/lang/StringBuilder 9: dup 10: aload_1 11: invokestatic #22 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 14: invokespecial #28 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 17: aload_2 18: bipush 15 20: bipush 19 22: invokevirtual #31 // Method java/lang/String.substring:(II)Ljava/lang/String; 25: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 28: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 31: astore_3 32: new #20 // class java/lang/StringBuilder 35: dup 36: aload_1 37: invokespecial #28 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 40: astore 4 42: aload 4 44: aload_2 45: bipush 15 47: bipush 19 49: invokevirtual #43 // Method java/lang/StringBuilder.append:(Ljava/lang/CharSequence;II)Ljava/lang/StringBuilder; 52: pop 53: aload 4 55: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 58: astore 5 60: return 
+5
source

The big advantage of option A, return x + creditCard.substring(15, 19); is that it is simple and clean and works in all versions of Java from 1 to 8 . If StringBuffer used in its compiled form, a simple recompilation for Java 5 or later will use StringBuilder instead. This flexibility is lost when working with a StringBuffer or StringBuilder manually.

The exact compiled form is not fixed. Since the semantics of the String.substring method String.substring not defined by the Java Language Specification, compilers usually do not touch this and compile it as a regular method call. The specification recommends that compiler providers use StringBuilder to concatenate strings (the + operator) whenever there is an advantage, and most compilers will do this, even if there is no benefit. Here both parameters x and the result of substring are String , so a simple String.concat will be simpler, but most compilers always use StringBuilder , compiling option A into the equivalent
return new StringBuilder().append(x).append(creditCard.substring(15, 19)).toString(); .

Comparing this typical form with your option B, we can conclude that option B has two performance advantages:

  • new StringBuilder(x) initializes a StringBuilder with a capacity of x.length()+16 , which is sufficient for the whole operation, while the default capacity new StringBuilder() , usually used for option A, is fixed at 16 characters, which skips the mark here, since we have the result of characters 19 , so the base array of characters will be redistributed and copied

  • sb.append(creditCard, 15, 19); copies four characters without having to create an intermediate String representation of these characters. The costs of a substring operation vary by implementation, for example. The Oracle implementation has undergone significant changes with version 1.7.0_06 ; starting with this version, the substring requires a new char[] array containing a copy of the damaged character data, since it does not support a separate offset and length field

But note that all these differences in options A and B only affect the formal description of the operation. What actually happens depends on the JVM / JRE, and as a rule, the Hotspot optimizer knows a lot of operations related to a string, and can smooth out operations or produce intermediate representations of strings. Thus, the result regarding performance is rather unpredictable and may be affected by minor changes in implementation .

That's why developers can stick with option A, which, as they say, is simpler and more readable, and only cares about performance, as soon as the profiler tells them that there is a performance problem that can be solved using StringBuilder manually.

+2
source

Source: https://habr.com/ru/post/1237041/


All Articles