I have the following class:
public class SeqGenerator {
int last = 0;
volatile int lastVolatile = 0;
public int getNext() {
return last++;
}
public synchronized int getNextSync() {
return last++;
}
public int getNextVolatile() {
return lastVolatile++;
}
public void caller() {
int i1 = getNext();
int i2 = getNextSync();
int i3 = getNextVolatile();
}
}
When I look at the disassembled code I don't see the difference between the representation of three methods getNext(), getNextSync() and getNextVolatile() .
public int getNext();
Code:
0: aload_0
1: dup
2: getfield #2; //Field last:I
5: dup_x1
6: iconst_1
7: iadd
8: putfield #2; //Field last:I
11: ireturn
public synchronized int getNextSync();
Code:
0: aload_0
1: dup
2: getfield #2; //Field last:I
5: dup_x1
6: iconst_1
7: iadd
8: putfield #2; //Field last:I
11: ireturn
public int getNextVolatile();
Code:
0: aload_0
1: dup
2: getfield #3; //Field lastVolatile:I
5: dup_x1
6: iconst_1
7: iadd
8: putfield #3; //Field lastVolatile:I
11: ireturn
public void caller();
Code:
0: aload_0
1: invokevirtual #4; //Method getNext:()I
4: istore_1
5: aload_0
6: invokevirtual #5; //Method getNextSync:()I
9: istore_2
10: aload_0
11: invokevirtual #6; //Method getNextVolatile:()I
14: istore_3
15: return
How the JMV can distinguish between these methods?
The generated code is the same of these methods and also of their callers. How the JVM performs the synchronization?
The synchronized keyword applied to a method just sets the ACC_SYNCHRONIZED flag on that method definition, as defined in the JVM specification § 4.6 Methods. It won't be visible in the actual bytecode of the method.
The JLS § 8.4.3.6 synchronized Methods discusses the similarity of defining a synchronized method and declaring a synchronized block that spans the whole method body (and using the same object to synchronize on): the effect is exactly the same, but they are represented differently in the .class file.
A similar effect happens with volatile fields: It simply sets the ACC_VOLATILE flag on the field (JVM § 4.5 Fields). The code that accesses the field uses the same bytecode, but acts slightly different.
Also please note that using only a volatile field here is not threadsafe, because x++ on a volatile field x is not atomic!
The difference between the first two is right here:
public int getNext();
bytecodes follow...
public synchronized int getNextSync();
bytecodes follow...
As to the last one, volatile is a property of the variable, not of the method or the JVM bytecodes that access that variable. If you look at the top of the javap output, you'll see the following:
int last;
volatile int lastVolatile;
If/when the bytecodes are compiled into machine code by the JIT compiler, I am sure the resulting machine code will differ for the last method.
Related
Version: scala 2.11.8
I defined a class with specialized type and override method in inheritance:
class Father[#specialized(Int) A]{
def get(from: A): A = from
}
class Son extends Father[Int]{
override def get(from: Int): Int = {
println("Son.get")
super.get(from)
}
}
new Son().get(1) // will cause infinite recursion
So, how to reuse the method of superclass with specialized annotation?
From the article Quirks of Scala Specialization:
Avoid super calls
Qualified super calls are (perhaps fundamentally) broken with specialization. Rewiring the super-accessor methods properly in the specialization phase is a nightmare that has not been solved so far. So, avoid them like the plague, at least for now. In particular, stackable modifications pattern will not work with it well.
So it's most likely a compiler bug, in general you shouldn't use super calls with Scala specialization.
After a bit of investigation:
javap -c Son.class
public class Son extends Father$mcI$sp {
public int get(int);
Code:
0: aload_0
1: iload_1
2: invokevirtual #14 // Method get$mcI$sp:(I)I
5: ireturn
public int get$mcI$sp(int);
Code:
0: getstatic #23 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #25 // String Son.get
5: invokevirtual #29 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: aload_0
9: iload_1
10: invokespecial #31 // Method Father$mcI$sp.get:(I)I
13: ireturn
Son.get(int) calls Son.get$mcI$sp(int) which turns into Father$mcI$sp.get(int):
javap -c Father\$mcI\$sp.class
public class Father$mcI$sp extends Father<java.lang.Object> {
public int get(int);
Code:
0: aload_0
1: iload_1
2: invokevirtual #12 // Method get$mcI$sp:(I)I
5: ireturn
public int get$mcI$sp(int);
Code:
0: iload_1
1: ireturn
Looks like we have found the cause - Father$mcI$sp.get(int) makes a virtual call to get$mcI$sp, which is overloaded in Son! This is what caused the infinite recursion here.
The compiler has to create specialized versions of method get which is get$mcI$sp, in order to support the non-specialized generic version of Father[T], which unfortunately makes it impossible to have super calls with specialized classes.
Now what happens after changing Father to be a trait (with Scala 2.12):
javap -c Son.class
public class Son implements Father$mcI$sp {
public int get$mcI$sp(int);
Code:
0: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #27 // String Son.get
5: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: aload_0
9: iload_1
10: invokestatic #37 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
13: invokestatic #43 // InterfaceMethod Father.get$:(LFather;Ljava/lang/Object;)Ljava/lang/Object;
16: invokestatic #47 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
19: ireturn
It looks like instead of calling get$mcI$sp in a parent class, it invokes static method Father.get$:
javap -c Father.class
public interface Father<A> {
public static java.lang.Object get$(Father, java.lang.Object);
Code:
0: aload_0
1: aload_1
2: invokespecial #17 // InterfaceMethod get:(Ljava/lang/Object;)Ljava/lang/Object;
5: areturn
public A get(A);
Code:
0: aload_1
1: areturn
public static int get$mcI$sp$(Father, int);
Code:
0: aload_0
1: iload_1
2: invokespecial #26 // InterfaceMethod get$mcI$sp:(I)I
5: ireturn
public int get$mcI$sp(int);
Code:
0: aload_0
1: iload_1
2: invokestatic #33 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
5: invokeinterface #17, 2 // InterfaceMethod get:(Ljava/lang/Object;)Ljava/lang/Object;
10: invokestatic #37 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
13: ireturn
What's interesting here, is that it seems like the get method is not getting real specialization since it has to box the value in get$mcI$sp, which might be a bug, or maybe specialization support for traits was dropped in Scala 2.12.
When we create a final in java it is guaranteed that it cannot be changed even at run time because the JVM guarantees it.
Java class:
public class JustATest {
public final int x = 10;
}
Javap decompiled:
Compiled from "JustATest.java"
public class JustATest {
public final int x;
public JustATest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #2 // Field x:I
10: return
}
But in scala, if we declare a val, it compiles into a normal integer and there is no difference between var and val in terms of decompilation output.
Original Scala class:
class AnTest {
val x = 1
var y = 2
}
Decompiled output:
Compiled from "AnTest.scala"
public class AnTest {
public int x();
Code:
0: aload_0
1: getfield #14 // Field x:I
4: ireturn
public int y();
Code:
0: aload_0
1: getfield #18 // Field y:I
4: ireturn
public void y_$eq(int);
Code:
0: aload_0
1: iload_1
2: putfield #18 // Field y:I
5: return
public AnTest();
Code:
0: aload_0
1: invokespecial #25 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #14 // Field x:I
9: aload_0
10: iconst_2
11: putfield #18 // Field y:I
14: return
}
With that information, the concept of immutability of a val is controlled only at compile time by the scala compiler? How is this guaranteed at run time?
In Scala, conveying immutability via val is a compile time enforcement which has nothing to do with the emitted byte code. In Java, you state that when the field is final in order for it not to be reassigned, where in Scala, declaring a variable with val only means it can't be reassigned, but it can be overridden. If you want a field to be final, you'll need to specify it as you do in Java:
class AnTest {
final val x = 10
}
Which yields:
public class testing.ReadingFile$AnTest$1 {
private final int x;
public final int x();
Code:
0: bipush 10
2: ireturn
public testing.ReadingFile$AnTest$1();
Code:
0: aload_0
1: invokespecial #19 // Method java/lang/Object."<init>":()V
4: return
}
Which is equivalent to the byte code you see in Java, except the compiler has emitted a getter for x.
The really simple answer is: there are some Scala features which can be encoded in JVM bytecode, and some which can't.
In particular, there are some constraints which cannot be encoded in JVM bytecode, e.g. sealed or private[this], or val. Which means that if you get your hands on the compiled JVM bytecode of a Scala source file, then you can do stuff that you can't do from Scala by interacting with the code through a language that is not Scala.
This is not specific to the JVM backend, you have similar, and even more pronounced problems with Scala.js, since the compilation target here (ECMAScript) offers even less ways of expressing constraints than JVM bytecode does.
But really, this is just a general problem: I can take a language as safe and pure as Haskell, compile it to native code, and if I get my hands on the compiled binary, all safety will be lost. In fact, most Haskell compilers perform (almost) complete type erasure, so there are literally no types, and no type constraints left after compilation.
I need to convert an ordinal int value to an enum value in Java. Which is simple:
MyEnumType value = MyEnumType.values()[ordinal];
The values() method is implicit, and I cannot locate the source code for it, hence the question.
Does the MyEnumType.values() allocate a new array or not? And if it does, should I cache the array when first called? Suppose that the conversion will be called quite often.
Yes.
Java doesn't have mechanism which lets us create unmodifiable array. So if values() would return same mutable array, we risk that someone could change its content for everyone.
So until unmodifiable arrays will be introduced to Java, for safety values() must return new/separate array holding all values.
We can test it with == operator:
MyEnumType[] arr1 = MyEnumType.values();
MyEnumType[] arr2 = MyEnumType.values();
System.out.println(arr1 == arr2); //false
If you want to avoid recreating this array you can simply store it and reuse result of values() later. There are few ways to do it, like.
you can create private array and allow access to its content only via getter method like
private static final MyEnumType[] VALUES = values();// to avoid recreating array
MyEnumType getByOrdinal(int){
return VALUES[int];
}
you can store result of values() in unmodifiable collection like List to ensure that its content will not be changed (now such list can be public).
public static final List<MyEnumType> VALUES = Collections.unmodifiableList(Arrays.asList(values()));
Theoretically, the values() method must return a new array every time, since Java doesn't have immutable arrays. If it always returned the same array it could not prevent callers muddling each other up by modifying the array.
I cannot locate the source code for it
The values() method has no ordinary source code, being compiler-generated. For javac, the code that generates the values() method is in com.sun.tools.javac.comp.Lower.visitEnumDef. For ECJ (Eclipse's compiler), the code is in org.eclipse.jdt.internal.compiler.codegen.CodeStream.generateSyntheticBodyForEnumValues.
An easier way to find the implementation of the values() method is by disassembling a compiled enum. First create some silly enum:
enum MyEnumType {
A, B, C;
public static void main(String[] args) {
System.out.println(values()[0]);
}
}
Then compile it, and disassemble it using the javap tool included in the JDK:
javac MyEnumType.java && javap -c -p MyEnumType
Visible in the output are all the compiler-generated implicit members of the enum, including (1) a static final field for each enum constant, (2) a hidden $VALUES array containing all the constants, (3) a static initializer block that instantiates each constant and assigns each one to its named field and to the array, and (4) the values() method that works by calling .clone() on the $VALUES array and returning the result:
final class MyEnumType extends java.lang.Enum<MyEnumType> {
public static final MyEnumType A;
public static final MyEnumType B;
public static final MyEnumType C;
private static final MyEnumType[] $VALUES;
public static MyEnumType[] values();
Code:
0: getstatic #1 // Field $VALUES:[LMyEnumType;
3: invokevirtual #2 // Method "[LMyEnumType;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LMyEnumType;"
9: areturn
public static MyEnumType valueOf(java.lang.String);
Code:
0: ldc #4 // class MyEnumType
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class MyEnumType
9: areturn
private MyEnumType(java.lang.String, int);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #8 // Method values:()[LMyEnumType;
6: iconst_0
7: aaload
8: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
11: return
static {};
Code:
0: new #4 // class MyEnumType
3: dup
4: ldc #10 // String A
6: iconst_0
7: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #12 // Field A:LMyEnumType;
13: new #4 // class MyEnumType
16: dup
17: ldc #13 // String B
19: iconst_1
20: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #14 // Field B:LMyEnumType;
26: new #4 // class MyEnumType
29: dup
30: ldc #15 // String C
32: iconst_2
33: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #16 // Field C:LMyEnumType;
39: iconst_3
40: anewarray #4 // class MyEnumType
43: dup
44: iconst_0
45: getstatic #12 // Field A:LMyEnumType;
48: aastore
49: dup
50: iconst_1
51: getstatic #14 // Field B:LMyEnumType;
54: aastore
55: dup
56: iconst_2
57: getstatic #16 // Field C:LMyEnumType;
60: aastore
61: putstatic #1 // Field $VALUES:[LMyEnumType;
64: return
}
However, the fact that the values() method has to return a new array, doesn't mean the compiler has to use the method. Potentially a compiler could detect use of MyEnumType.values()[ordinal] and, seeing that the array is not modified, it could bypass the method and use the underlying $VALUES array. The above disassembly of the main method shows that javac does not make such an optimization.
I also tested ECJ. The disassembly shows ECJ also initializes a hidden array to store the constants (although the Java langspec doesn't require that), but interestingly its values() method prefers to create a blank array then fill it with System.arraycopy, rather than calling .clone(). Either way, values() returns a new array every time. Like javac, it doesn't attempt to optimize the ordinal lookup:
final class MyEnumType extends java.lang.Enum<MyEnumType> {
public static final MyEnumType A;
public static final MyEnumType B;
public static final MyEnumType C;
private static final MyEnumType[] ENUM$VALUES;
static {};
Code:
0: new #1 // class MyEnumType
3: dup
4: ldc #14 // String A
6: iconst_0
7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #19 // Field A:LMyEnumType;
13: new #1 // class MyEnumType
16: dup
17: ldc #21 // String B
19: iconst_1
20: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #22 // Field B:LMyEnumType;
26: new #1 // class MyEnumType
29: dup
30: ldc #24 // String C
32: iconst_2
33: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #25 // Field C:LMyEnumType;
39: iconst_3
40: anewarray #1 // class MyEnumType
43: dup
44: iconst_0
45: getstatic #19 // Field A:LMyEnumType;
48: aastore
49: dup
50: iconst_1
51: getstatic #22 // Field B:LMyEnumType;
54: aastore
55: dup
56: iconst_2
57: getstatic #25 // Field C:LMyEnumType;
60: aastore
61: putstatic #27 // Field ENUM$VALUES:[LMyEnumType;
64: return
private MyEnumType(java.lang.String, int);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #31 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
public static void main(java.lang.String[]);
Code:
0: getstatic #35 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #41 // Method values:()[LMyEnumType;
6: iconst_0
7: aaload
8: invokevirtual #45 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
11: return
public static MyEnumType[] values();
Code:
0: getstatic #27 // Field ENUM$VALUES:[LMyEnumType;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class MyEnumType
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #53 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static MyEnumType valueOf(java.lang.String);
Code:
0: ldc #1 // class MyEnumType
2: aload_0
3: invokestatic #59 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class MyEnumType
9: areturn
}
However, it's still potentially possible that the JVM could have an optimization that detects the fact that the array is copied and then thrown away, and avoids it. To test that, I ran the following pair of benchmark programs that test ordinal lookup in a loop, one which calls values() each time and the other that uses a private copy of the array. The result of the ordinal lookup is assigned to a volatile field to prevent it being optimized away:
enum MyEnumType1 {
A, B, C;
public static void main(String[] args) {
long t = System.nanoTime();
for (int n = 0; n < 100_000_000; n++) {
for (int i = 0; i < 3; i++) {
dummy = values()[i];
}
}
System.out.printf("Done in %.2f seconds.\n", (System.nanoTime() - t) / 1e9);
}
public static volatile Object dummy;
}
enum MyEnumType2 {
A, B, C;
public static void main(String[] args) {
long t = System.nanoTime();
for (int n = 0; n < 100_000_000; n++) {
for (int i = 0; i < 3; i++) {
dummy = values[i];
}
}
System.out.printf("Done in %.2f seconds.\n", (System.nanoTime() - t) / 1e9);
}
public static volatile Object dummy;
private static final MyEnumType2[] values = values();
}
I ran this on Java 8u60, on the Server VM. Each test using the values() method took around 10 seconds, while each test using the private array took around 2 seconds. Using the -verbose:gc JVM argument showed there was significant garbage collection activity when the values() method was used, and none when using the private array. Running the same tests on the Client VM, the private array was still fast, but the values() method became even slower, taking over a minute to finish. Calling values() also took longer the more enum constants were defined. All this indicates that the values() method really does allocate a new array each time, and that avoiding it can be advantageous.
Note that both java.util.EnumSet and java.util.EnumMap need to use the array of enum constants. For performance they call JRE proprietary code that caches the result of values() in a shared array stored in java.lang.Class. You can get access to that shared array yourself by calling sun.misc.SharedSecrets.getJavaLangAccess().getEnumConstantsShared(MyEnumType.class), but it is unsafe to depend on it as such APIs are not part of any spec and can be changed or removed in any Java update.
Conclusion:
The enum values() method has to behave as if it always allocates a new array, in case callers modify it.
Compilers or VMs could potentially optimize that allocation away in some cases, but apparently they don't.
In performance-critical code, it is well worth taking your own copy of the array.
when I run javap -c Address.class > Address.txt on a particular class,
I get a bunch of output, with #<NUMBER> as the index to the constant pool
Compiled from "Address.java"
public class test.Address extends test.Entity {
public test.Address();
Code:
0: aload_0
1: invokespecial #1 // Method test/DefaultEntity."<init>":()V
4: aload_0
5: aconst_null
6: putfield #2 // Field io:Ljava/lang/String;
9: aload_0
10: aconst_null
11: putfield #3 // Field zip4:Ljava/lang/String;
14: aload_0
15: aconst_null
16: putfield #4 // Field zip:Ljava/lang/String;
19: aload_0
How would I be able to get the pool in the form of a hashmap? i.e:
{1 "Method test/DefaultEntity."<init>":()"
2 "Field io:Ljava/lang/String;"}
With ASM, you can use a ClassReader to read a .class file and then use getItemCount() and the various read methods to read all of the constant pool items.
(def cr (clojure.asm.ClassReader "test.Address"))
(.getItemCount cr)
;; etc
Which one is more optimal or is there any difference at all?
String s = methodThatReturnsString();
int i = methodThatReturnsInt();
thirdMethod(s, i);
or
thirdMethod(methodThatReturnsString(), methodThatReturnsInt());
By optimal I mean optimal in the terms of memory usage etc.
It has nothing to do with optimization here, but it's more a question of readability of your code...
Which one is more optimal?
The one which is easier to read :-)
I would think that any difference is optimized away when compiled (provided that the declared variables are not used afterwards - i.e. the solutions are otherwise identical).
I highly suspect that both forms are identical, but don't take my word for it. Let's find out ourselves! :D
public class Tests {
public void test1() {
String s = methodThatReturnsString();
int i = methodThatReturnsInt();
thirdMethod(s, i);
}
public void test2() {
thirdMethod(methodThatReturnsString(), methodThatReturnsInt());
}
public String methodThatReturnsString() {
return "";
}
public int methodThatReturnsInt() {
return 0;
}
public void thirdMethod(String s, int i) {
}
}
Let's compile it:
> javac -version
javac 1.6.0_17
> javac Tests.java
Now, let's print out the bytecode instructions!
> javap -c Tests
Compiled from "Tests.java"
public class Tests extends java.lang.Object{
public Tests();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public void test1();
Code:
0: aload_0
1: invokevirtual #2; //Method methodThatReturnsString:()Ljava/lang/String;
4: astore_1
5: aload_0
6: invokevirtual #3; //Method methodThatReturnsInt:()I
9: istore_2
10: aload_0
11: aload_1
12: iload_2
13: invokevirtual #4; //Method thirdMethod:(Ljava/lang/String;I)V
16: return
public void test2();
Code:
0: aload_0
1: aload_0
2: invokevirtual #2; //Method methodThatReturnsString:()Ljava/lang/String;
5: aload_0
6: invokevirtual #3; //Method methodThatReturnsInt:()I
9: invokevirtual #4; //Method thirdMethod:(Ljava/lang/String;I)V
12: return
public java.lang.String methodThatReturnsString();
Code:
0: ldc #5; //String
2: areturn
public int methodThatReturnsInt();
Code:
0: iconst_0
1: ireturn
public void thirdMethod(java.lang.String, int);
Code:
0: return
}
I thought this looked a bit strange - test1() and test2() are different. It looks like the compiler is adding the debugging symbols. Perhaps this is forcing it to explicitly assign return values to the local variables, introducing extra instructions.
Let's try recompiling it with no debugging:
> javac -g:none Tests.java
> javap -c Tests
public class Tests extends java.lang.Object{
public Tests();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public void test1();
Code:
0: aload_0
1: invokevirtual #2; //Method methodThatReturnsString:()Ljava/lang/String;
4: astore_1
5: aload_0
6: invokevirtual #3; //Method methodThatReturnsInt:()I
9: istore_2
10: aload_0
11: aload_1
12: iload_2
13: invokevirtual #4; //Method thirdMethod:(Ljava/lang/String;I)V
16: return
public void test2();
Code:
0: aload_0
1: aload_0
2: invokevirtual #2; //Method methodThatReturnsString:()Ljava/lang/String;
5: aload_0
6: invokevirtual #3; //Method methodThatReturnsInt:()I
9: invokevirtual #4; //Method thirdMethod:(Ljava/lang/String;I)V
12: return
public java.lang.String methodThatReturnsString();
Code:
0: ldc #5; //String
2: areturn
public int methodThatReturnsInt();
Code:
0: iconst_0
1: ireturn
public void thirdMethod(java.lang.String, int);
Code:
0: return
}
Inconceivable!
So, according to my compiler (Sun JDK), the bytecode is shorter for the second version. However, the virtual machine will probably optimize any differences away. :)
Edit: Some extra clarification courtesy of Joachim Sauer's comment:
It's important to note that the byte
code tells only half the story: How it
is actually executed depends a lot on
the JVM (that's quite different to
C/C++, where you can see the assembler
code and it's exactly how it's
executed). I think you realize that,
but I think it should be made clearer
in the post.
I would prefer the first option. However this has nothing to do with speed, but with debuggability. In the second option I can not easily check what the values of s and i are. Performance-wise this will not make any difference at all.
There shouldn't be any difference. Both the temporarily used String and int have to reside somewhere and Java is, internally, a stack machine. So regardless of whether you give the return values of that method calls names or not, they have to be stored on the stack prior to execution of thirdMethod(String, int).
Implications of that for the resulting JITted code can be hard to find. That's on a completely different level ob abstraction.
If in doubt, profile. But I wouldn't expect any difference here.
It is the same thing. In both cases the same functions will be called and variables (automatic or explicitly defined will be allocated). The only difference is that in the second case, the variables will be ready to garbage collected whereas on the first one you need to wait to get out of scope.
Of course however the first one is much more readable.
There is no difference at all. In this case, you might want to consider readability and clearness.
Experiment and measure. If speed is what matters, measure speed. If memory usage matters, measure memory usage. If number of bytecode instructions is what matters, count bytecode instructions. If code readability is what matters, measure code readability. Figuring out how to measure code readability is your homework.
If you don't experiment and measure all you get will be opinion and argument.
Or, if you are very lucky, someone on SO will run your experiments for you.
PS This post is, of course, my opinion and argument
thirdMethod(metodThatReturnsString(), metodThatReturnsInt());
is more optimal...