Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize a local variable in Java only once

In C++, the following code:

#include <stdio.h>

static const char *init()
{
    printf("in init()\n");
}

static void func()
{
    static const char *str = init();
    printf("in func()\n");
}

int main()
{
    for (int i=0; i<10; ++i) {
        func();
    }
    return 0;
}

shows that the despite the numerous invokations of the func(), str is only initialized once by printing a trace message in the function init() used to initialize str. When run, there are a total of 10 lines of trace, once for init() and 10 times for func()

In Java, shouldn't the following code do the same thing?

class test {
    private String init()
    {
        System.out.println("in init()");
        return "FOO";
    }

    private void func()
    {
        final String str = init();
        System.out.println("in func()");
    }

    public test()
    {
        for (int i=0; i<10; ++i) {
            func();
        }
    }

    public static main(String[] args)
    {
        test app = new test();
    }
}

When run, there are 20 lines of output, 10 each for init() and func(). Based on what I read about final variables, I thought it would behave the same way. So I tried static final and it would not compile (nor just static) Is there a way to do this? I need to call a time-consuming initialization function from several different methods in my class, so just moving the variable to class scope wouldn't work. Further, since local variables are not automatically initialized, I cannot include an if test for null around the variable before assigning it a value. I suppose I could create a variable at in the class scope for each method in my class, but managing it would be a pain to manage. The best analogy would be something if I were to include something like the following in every method:

public myfunc1()
{
    final String funcName = java.lang.Thread.currentThread().getStackTrace()[1].getMethodName();
}
public myfunc2()
{
    final String funcName = java.lang.Thread.currentThread().getStackTrace()[1].getMethodName();
}

funcName in this case will get a unique value in each method, but the initialization is expensive.

like image 232
Xaq Avatar asked Jun 07 '13 16:06

Xaq


2 Answers

The following is a fairly close approximation:

class test {

    private static final String str = init();

    private static String init()
    {
        System.out.println("in init()");
        return "FOO";
    }

    private void func()
    {
        System.out.println("in func()");
    }

    public test()
    {
        for (int i=0; i<10; ++i) {
            func();
        }
    }

    public static void main(String[] args)
    {
        test app = new test();
    }
}

Note that str is initialized when the class is loaded, not when func() is called for the first time.

like image 78
NPE Avatar answered Oct 03 '22 22:10

NPE


The final qualifier makes the variable constant through a single method call.

Since you want a single value per instance, you can use an instance member variable, outside the method.

private final String str = init();

private void func()
{
    System.out.println("in func()");
}

If you wanted a single value across all method calls for all instances, you could use a static member variable, outside the method.

private static final String str = init();

private void func()
{
    System.out.println("in func()");
}
like image 23
Andy Thomas Avatar answered Oct 03 '22 22:10

Andy Thomas