【问题标题】:How to initialise a final variable that requires complex computation?如何初始化需要复杂计算的最终变量?
【发布时间】:2016-07-04 01:32:43
【问题描述】:

我是 Java 的初学者。我想知道,如果变量在初始化之前需要复杂的计算,但一旦初始化,它就不会改变。我想使变量最终,但不是在构造函数中初始化它,我宁愿在一个方法中初始化它,以便以后可以重用这个方法。有没有办法实现这一目标?

除了上述所有要求之外,如果我只想在需要时计算这个变量的值,会发生什么(因为计算它的计算成本很高)。在这种情况下我该怎么办?

【问题讨论】:

  • 您总是可以编写一个计算最终变量值的方法,并在构造函数中调用该方法将返回值分配给最终变量。为什么不呢?
  • 对于第二个问题,您将布尔值传递给对象的构造函数 shouldInitializeFinalVariable 并根据该方法调用昂贵的方法,否则默认为无参数构造函数

标签: java variables methods constructor final


【解决方案1】:

你可以试试Guava的memoize供应商:

Supplier<T> something = Suppliers.memoize(new Supplier<T>() {
    // heavy computation
    return result.
});

something.get();
something.get(); // second call will return the memoized object.

【讨论】:

  • 不知道有多少除了谷歌自己的开发者在日常开发中使用Guava?
  • @svasa 如果你开发了一天没有使用 Guava,你可能做错了什么。
  • @shmosel 我不同意。在没有 Guava 的情况下,绝对可以编写整洁、高效、可维护、高可用的代码。另一方面,我知道 Guava 无疑是一个不错的库,是否所有组织都允许他们的开发人员使用它并发布具有 Guava 依赖项的产品?
【解决方案2】:

不幸的是,您不能在任何给定的时刻将变量设为final。如果变量是final,它可以(并且必须)在构造函数中初始化。

您也可以这样做(以下代码归功于 npinti):

private boolean isMutable;
private String someString;

public void setMutable(boolean value)
{
    this.isMutable = value;
}

public void setSomeString(String value)
{
    if (this.isMutable)
    {
        this.someString = value;
    }
}

【讨论】:

    【解决方案3】:

    看起来您需要延迟初始化。当由于某种原因认为结果很昂贵时,使用 use 是一种性能优化。目标是 延迟昂贵的计算,直到有必要为止 存储该昂贵计算的结果,这样计算就不需要再次重复。

    以下是一个例子:

    public final class Foo {
        private Data data = null; 
    
        private Data expensiveComputation() {
            if(data == null) { // first call to this method
                Data data = new Data();
                // complex computation
                // store the result to data
            } else {
                return data;
            }
        }
    }
    

    如您所见,data 仅在需要时才被初始化。

    请注意,如果您的代码在多线程环境中工作,则会出现问题。这是因为多个线程可以同时调用该方法。为了防止这种情况,我们可以使用synchronized 关键字:

    public final class Foo {
        private volatile Data data = null; 
    
        private Data expensiveComputation() {
            if(data == null) { // first call to this method
                synchronized(Foo.class) {
                    if(data == null) {
                        Data data = new Data();
                        // complex computation
                        // store the result to data
                    }
                }
            } else {
                return data;
            }
        }
    }
    

    synchronized关键字只允许一个线程可以进入并初始化data

    【讨论】:

    • 最后一个例子不适用于多线程,除非数据是可变的。
    猜你喜欢
    • 2014-06-20
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 2023-04-02
    • 2016-11-25
    • 1970-01-01
    相关资源
    最近更新 更多