因此,我们已将某些东西推向生产,并且它运作良好。但是,我在日志中看到一些非常令人不安的东西。即:
pr 0.1 - wait time for fetchAndRemoveEntries: 0
pr 1.0 - f'n'r entries: uid: hbyk68jfhbf5th
请注意,pr
对于这两行是不同的。对wait time for fetchAndRemoveEntries
运行代码搜索只返回一个结果,f'n'r entries
也是如此。两者都是println
。第一个是在我们的API类中找到的:
System.out.println("pr " + NotificationDataStorage.printReduction + " - wait time for fetchAndRemoveEntries: " + (System.currentTimeMillis() - startTime));
第二个是在NotificationDataStorage类中找到的,其中定义了printReduction。该类的缩写版本:
public class NotificationDataStorage {
public static final double printReduction = 1;
...
public static void addEntries(ArrayList<HashMap> data) {
... // No, I have did not declare 'printReduction' as a local variable.)
System.out.println("pr " + printReduction + " - adding " + data.size() + " entries");
...
}
...
}
甚至忽略了&#34; addEntries&#34;代码,NotificationDataStorage.printReduction返回0.1的事实,实际上它应该是1,这是非常令人担忧的。
我们整个星期都一直困扰着这样的问题,但到目前为止,当我们推送到服务器时,它们总是消失。我们假设它们是本地的怪癖,也许是NetBeans的缺陷。我在调试器中逐步执行代码,查看一个常量,因为它被传递到方法A中,并且当我在A的范围内时,看到它从先前的构建中更改为值。旧值导致代码崩溃。我把它设置为记录一些东西,问题神秘地消失了。我们的代码莫名其妙地无法正常工作,但在检查了一个不同的分支并检查了返回不工作的分支后,它突然又开始工作了。清洁和建筑有时会修复它。有时不会。
部分奇怪的是,这是我们遇到这些问题的第一周,尽我所知。好像一周前我们写了一些代码,它们的位现在召唤出一个与我们的常数混淆的恶魔。或者,更准确地说,就像我们更新常量时一样,更改仅反映在他们使用过的某些地方。
目前显而易见的特殊问题并不存在问题,但是其他常数可能会遇到类似的问题,这一点非常令人担忧。
是否有人对此有任何见解,经验或解释?
答案 0 :(得分:3)
这几乎可以肯定是由于并非所有代码都被重新编译。
您的字段为public static final double
,它将在编译时获得内联值。如果值发生变化,这是一个巨大的问题,因为未重新编译的旧类将不会更新其值!如果引用此字段的代码位于不同的jar中,则可能也不会重新编译。
The Java Security Coding Guidelines DCL59-J涵盖了这个问题
final关键字可用于指定常量值(即在程序执行期间无法更改的值)。但是,在程序的生命周期内可以更改的常量不应声明为public final。 Java语言规范(JLS)[JLS 2013]允许实现在任何读取字段的编译单元中内嵌任何公共final字段的值。因此,如果编辑声明类以便新版本为字段提供不同的值,则读取公共final字段的编译单元仍然可以看到旧值,直到它们被重新编译。例如,当第三方库更新到最新版本但未重新编译引用代码时,可能会出现此问题。
解决方案是创建字段private
并使用公共静态getter方法。
private static final double PRINT_REDUCTION = 1; //will change often
public static double getPrintReduction(){
return PRINT_REDUCTION;
}
注意我还将字段大写,这是常量的java编码约定。
中介绍了此主题和更多问题