【问题标题】:Incompatibilities between java versionsjava版本之间的不兼容
【发布时间】:2015-02-11 14:37:42
【问题描述】:

有一段复杂的代码可以执行许多复杂的数学运算。

当它在 jdk 1.7 上由 maven 构建和测试时,它通过了所有测试。 使用 jdk 1.8 时失败。

试图在调试器中找到计算出错的地方似乎几乎没有希望。

我有哪些选择?是否有工具可以扫描我的代码中 jdk 1.7 和 1.8 之间的不兼容性?

最好的选择是在两个单独的调试器中运行代码并查看差异在哪里?

编辑:

@Philipp Claßen 这是迄今为止最可能的原因。我希望有一种自动检查的方法。

@dkatzel 代码不是我写的,评论很差,而且做的科学计算对我来说是“木头”。

@迈克·塞缪尔 我认为这种方法与并行运行两个调试器相比没有任何好处。

感谢大家的帮助。似乎两个调试器是最好的方法。

编辑 2 原始代码的作者依赖于哈希映射排序。这就是问题所在。

【问题讨论】:

  • 查看发行说明以获取线索。否则,我认为您将不得不运行两个调试器。
  • 你能发一些代码吗?
  • 我可以保证看到代码不会有帮助。除非你想经历数千行。
  • 您描述了两个应该是五个的场景:1) 使用1.7 构建并在1.7 上测试/执行,2) 使用1.7 构建并在1.8 上测试/执行, 3) 使用1.8-target 1.7 构建并在1.7 上测试/执行,4) 使用1.8-target 1.7 构建并在1.8 上测试/执行,5) 使用1.8 和@987654332 构建@ 并在 1.8 上测试/执行。了解这些场景中的哪些失败或失败的场景是否/哪些会产生相同的结果会很有用。
  • 如果您怀疑可能存在依赖于HashMap 排序的代码,您可以在jdk1.7 上运行测试,在其中替换了执行不同顺序的HashMap 实现。如果这是与原始 jdk1.7 的唯一区别,您很快就会知道是否是问题所在。

标签: java java-8 java-7 incompatibility


【解决方案1】:

添加日志语句以记录每个中间结果。你可以使用类似的东西

static void dumpDoubleWithLineNumber(double d) {
  StackTraceElement[] stack = Thread.currentThread().getStackTrace();
  // Thread.getStackTrace() and this method are elements 0 and 1
  StackTraceElement caller = stack[2];
  System.err.println(
      caller.toString()
      + " : " + d 
      + " / " + Long.toString(Double.toLongBits(d), 16));
}

然后在 Java 7 下运行一次,在 Java 8 下运行一次,然后比较结果。

【讨论】:

  • 对不起,但考虑到他已经有测试用例,而且代码是几千行,这不是有点Hello World的做法吗?我宁愿从测试用例及其堆栈跟踪开始..
  • @Shaunak,我不知道 Hello World 方法是什么,但测试堆栈跟踪仅告诉您检测到故障的位置。来自一个失败测试的日志差异将告诉您差异从哪里开始。 1000 行是一个相当小的程序。放入几百条日志语句最多需要 20 分钟。尝试从测试失败中向后推理可能需要数小时或数天。
  • 正是我们编写测试用例的目的!并且看起来他已经有一套很好的测试用例来解决问题。
  • 我真的很喜欢这个解决方案。
  • @Shaunak,测试告诉安德烈存在问题,但安德烈尚未发现问题。遥测可以帮助解决这个问题。
【解决方案2】:

似乎您有一套很好的测试来发现问题。也许一个好的开始是比较通过的测试和失败的测试。失败的测试有何不同?

如果失败的测试做得太多,那么您需要更细粒度的测试。测试实际上应该只单独测试一件事。这意味着您应该进行大量测试来测试复杂计算的每个部分。

Java 的新版本确实努力不破坏旧的工作代码,因此它不太可能是 JDK 中的错误......但是有可能......

【讨论】:

    【解决方案3】:

    寻找不确定性的来源。

    尤其是依赖于集合中元素顺序的代码(如 HashMaps)是危险的,因为顺序未指定并且取决于 JVM。

    我在每次 JVM 升级中都看到,这种(错误)代码是靠运气工作的,一旦 JVM 实现发生变化,就会立即中断。

    【讨论】:

      【解决方案4】:

      如果有一个特定的对象,你想监控,并且改变对象的点不是太多,你可以尝试设置条件断点,它将信息打印到系统.out 而不是暂停线程。这适用于 eclipse,也可能适用于其他 IDE
      例如,要监控特定代码点的 d 值,您可以使用以下条件创建断点:

      System.out.println(Thread.currentThread().getStackTrace()[1] + " value="+d); return false;
      

      这个条件永远不会为真,但总是被评估,所以它会打印出类似的内容:

      test.Main.main(Main.java:23) value=1.0
      

      如果这在您的 IDE 中有效,您可以在 IDE 中使用 Java 7 和 Java 8 运行您的程序并比较输出。如果你能识别出差异所在的行,你可以继续进行常规调试。

      也许你可以在这里找到更多:http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-manage_conditional_breakpoint.htm

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-29
        • 1970-01-01
        • 2020-02-14
        • 2012-09-30
        • 2018-10-18
        相关资源
        最近更新 更多