Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java for loop optimizations

What sort of optimizations would Java Runtime perform on the follow snippet of code? The bytecode doesn't reveal any optimization however I feel that Java should take the last value of the for loop without running the entire for loop since String is a rudimentary Java class.

NOTE. this question was asked on a class test; however, I couldn't provide enough evidence to back my claim.

public class Main {

    public static void main(String[] args) {
        String str = null;
        for (long i = 0; i < 10000000000L; i++) {
            str = new String("T");
        }

        System.out.println(str);
    }
}
like image 301
Mathew Kurian Avatar asked Nov 09 '22 00:11

Mathew Kurian


1 Answers

While I can't speak to exactly what the jit compiler is doing, the optimization you are asking it to do (to determine that it is safe to skip the loop body entirely) is actually extremely difficult to do, and so I highly doubt it it is done. This is true regardless of String being a "rudimentary Java class".

To understand better, first let's assume that instead of String, we are creating instances of an arbitrary class Foo. It would only be safe to skip the creation of all those Foo objects if we knew two things: that calling new Foo() didn't have any observable side effects; and that no references to Foo "escaped" the loop body.

An observable side effect would be something like setting the value of a static member (e.g. if the Foo class kept a static count of all the times Foo() had been called). An example of a reference escaping would be if the this variable inside of Foo() was passed somewhere else.

Note that it isn't enough to just look at Foo(), you need to look at Foo's superclass' constructor (and all the way up the chain to Object). And then you need to look at all the code that gets executed upon initialization of each of those objects. And then look at all the code that gets called by that code. That would be a tremendous amount of analysis to do "just-in-time".

public class Foo extends Bazz{
    static int count = 0;

    public Foo(){
        // Implicit call to Bazz() has side effect
        count++; // side effect
        Bazz.onNewFoo(this); // reference escaping
    }

    Bazz bazz = new Bazz();  // side effect
    {
        Bazz.onNewBazz(this.bazz); // reference escaping
    }
}

class Bazz{
    static int count = 0;

    static List<Foo> fooList = new LinkedList<>();
    static List<Bazz> bazzList = new LinkedList<>();

    static void onNewFoo(Foo foo){
        fooList.add(foo);
    }

    static void onNewBazz(Bazz bazz){
        bazzList.add(bazz);
    }

    public Bazz(){
        count++;
    }
}

You might think we should just let javac do this analysis and optimization for us. The problem with that is, that there is no way to guarantee that the version of Foo() that was on the classpath at compile-time will be the same as that which is on the classpath at run-time. (Which is a very valuable feature of Java - it allows me to move my application from Glassfish to Tomcat without recompiling). So we can't trust analysis done at compile-time.

Finally, realize that String is no different from Foo. We'd still need to run that analysis, and there is no way to do that analysis in advance (which I why I can upgrade my JRE without recompiling my apps)

like image 171
dan.m was user2321368 Avatar answered Nov 14 '22 22:11

dan.m was user2321368