【问题标题】:Strategies for migrating medium-sized code base from Java 1.4.2 to Java 5将中型代码库从 Java 1.4.2 迁移到 Java 5 的策略
【发布时间】:2010-10-18 00:59:56
【问题描述】:

我正在审查代码库 (~20K LOC) 并尝试确定如何将其从 1.4.2 迁移到 5。显然,这不是一个一夜之间的项目,我收到的建议是针对 Java 5 编写新代码并以零碎的方式迁移旧代码。此外,我不是 Java 5 新特性的专家(即我知道它们,但从未编写过任何用于生产用途的东西)。

我的问题:

  1. Java 5 的哪些特性通常用于生产代码? (即泛型、自动装箱等)是否有要避免/不被视为最佳实践的功能?

  2. 我可以使用哪些最佳重构策略来迁移这种大小的代码库? (即仅在编辑类时一次更改一个类等) 目标 - 降低代码库的风险。限制 - 进行重构的资源。

感谢任何建议 - 提前致谢。

更新 - 晚了一年,但迟到总比没有好? =)

感谢所有 cmets - 很多很棒的观点。在软件开发人员的生活中,总会有一些您努力完成但由于更“紧急”的事情而无法完成的项目。

关于Java 5的使用(当时),是客户生产环境需要的东西,所以我们没有使用Java 6。

我发现集合、枚举和拆箱的更强类型是我最倾向于应用的功能,无论是旧代码还是新代码。重构相当简单,但代码理解显着提高,标准变得更容易执行。我最麻烦的是泛型。我认为这是一个我还没有机会完全掌握和欣赏的概念,所以我很难找到以前应用泛型的案例。

再次感谢为此线程做出贡献的所有人,并对迟到的跟进表示歉意。

【问题讨论】:

  • 我希望您使用 IntelliJ 等,因为它对大多数更改都有自动修复。
  • @Peter 不幸的是,我们无法访问 IntelliJ。只是 Eclipse。
  • IntelliJ 社区版是免费的。您可以将它用作 JDK 1.4 到 5.0 的迁移工具,仅此而已。 ;) 我曾经做过的最多的自动修复/转换并从一次运行中签入是 7K。 :P

标签: java refactoring migration


【解决方案1】:

Java 5 几乎完全向后兼容 Java 4。通常,您在迁移时必须进行的唯一更改是重命名 Java 4 代码中新的 enum 关键字的任何用法。

此处列出了潜在兼容性问题的完整列表:

http://java.sun.com/j2se/1.5.0/compatibility.html

我在实践中遇到的唯一其他问题与 JAXP 实现中的更改有关。在我们的例子中,它只是意味着从类路径中删除 xerces.jar。

就重构而言,我认为迁移您的集合类以使用新的强类型泛型版本并删除不必要的转换是一个好主意。但正如另一位海报指出的那样,如果您在垂直切片中工作,则更改为通用集合往往效果最好。否则,您最终必须在代码中添加强制转换,以使泛型类型与非泛型类型兼容。

我在迁移代码时喜欢使用的另一个功能是@Override 注释。它有助于在重构代码时发现继承问题。

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html

如果您的代码使用线程,则新的并发库非常有用。例如,您可以用ThreadPoolExecutor 替换自制线程池。

http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html#concurrency

当您在正常维护期间更改代码时,我肯定会采用更新代码的方法。除了兼容性问题,我认为没有令人信服的理由使用新的 Java 5 功能,除非您已经出于其他原因更改了代码。

【讨论】:

  • +1 表示从 1.4 迁移到 5 似乎不是一项艰巨的任务,尤其是对于像原始海报这样的小型项目。
【解决方案2】:

泛型的“病毒”性质存在一个非常现实的问题。一旦您开始在架构中的给定层引入它们,您通常也希望在上层和下层引入它们。我发现引入泛型可能最好在完整的“垂直”中完成。但是您不必一次完成所有垂直行业。

【讨论】:

    【解决方案3】:

    这是一个很难回答的问题,因为它取决于哪些代码会受到影响以及该代码的重要性。

    首先,当迁移是一项艰巨的任务时,请帮自己一个忙,升级到 Java 的最新版本,这将是 Java 6 而不是 Java 5。Java 6 已经推出一年半或更长时间,并且是成熟的。没有理由不选择 Java 5(恕我直言)。

    其次,与任何软件项目一样,您的目标应该是尽快将某些东西投入生产。因此,您需要识别系统的一部分。越小越好,越非关键性越好。

    要做的另一件事是尝试在 Java 6 下启动您的应用程序,然后看看有什么问题。它可能比你预期的更糟。可能会好很多。

    您可能需要注意的另一件事是,您的应用中的 jars/libraries 听起来已经被弃用了。有些甚至可能与 1.4.2 之后的 Java 不兼容。您可能还想将所有这些都升级到最新版本。

    这可能意味着更多的东西会被破坏,但使​​用旧的/已弃用的 API 只会把罐子踢到街上并给你带来其他问题。

    升级可能会产生深远影响的例外情况。想到 Axis1 到 Axis2。这些情况需要更仔细的考虑。

    至于使用了哪些功能……都差不多。我想不出任何应该避免的事情。

    另外,我刚刚注意到您的项目的大小:~20K LOC。这实际上非常小(例如,我在过去 3 个月里自己编写了一个这种大小的应用程序)。

    最后,这还取决于您找到损坏的东西的难易程度。如果您有良好的单元测试覆盖率,那就太好了。不过,这非常罕见。如果您可以通过应用程序运行并可靠地发现问题,那还不错。

    有问题的情况是场景难以测试并且您可能不会立即发现问题。这需要更加谨慎。

    【讨论】:

    • J2SE 5.0 处于其服务生命周期终止期。如果可以的话,Java SE 6。
    【解决方案4】:

    您可能希望迁移在从 1.4 到 5 的过渡中不起作用的东西(不确定那会是什么),但我会警惕为了而迁移的东西它。

    如果你确实走这条路,一些问题:

    您是否有全面的测试覆盖率?如果没有,您应该为要迁移的代码编写单元测试。

    您的代码库中是否有广泛使用的组件?如果是这样,就其 API 而言,它们可能是迁移的候选对象(例如,使用泛型等)

    就 Java 5 中广泛使用的内容而言。泛型很重要,它可以让您的生活更轻松。我没有看到太多自动装箱 ,也没有枚举(这都是相对的)。 Varargs 几乎从不。注释对框架很有用,但我使用这些。我想我自己从来没有实现过。

    【讨论】:

      【解决方案5】:

      20 (non-comment) kloc 应该足够小以插入泛型。显然,请确保您的代码首先在 Java SE 5 上编译运行。关于泛型的相对简单的事情是添加它们对语义的改变很小(某些重载可能会因为隐含的情况而改变 - Iterator<char[]> iter; ... System.out.println(iter.next()); 是我脑海中的一个坏例子)。

      某些添加泛型的情况会突出代码的概念问题。例如,使用一个Map 作为两个具有不相交键集的映射。 TreeMap 是 Java 库中的一个示例,其中单个类具有两种不同的模式(使用 Comparator<T>Comparable<T>)。

      enhanced-for 和 auto-boxing 之类的东西是非常本地化的,可以逐个添加。枚举比较少见,可能需要考虑一下您将如何实际使用它们。

      【讨论】:

        【解决方案6】:

        我认为你的做法是错误的。您的计划不应该是将所有当前代码更新到 Java 1.5,您的计划应该是确保所有当前代码在 1.5 中的运行与在 1.4.2 中完全相同,并且所有未来编写的代码都将在 1.5 中正常运行.

        我已经经历了几次这样的不同大小的代码库的转换。我们的目标始终是确保我们有大量的单元测试,以便我们可以轻松插入 1.5 并通过它运行我们的测试。我们实际上遇到了大约 10 个问题,主要与正则表达式库不支持某些东西或支持不同的东西有关。

        然后在 1.5 中编写所有新代码,如果您出于某种原因更改了旧类,请花一分钟时间实现泛型,但没有理由重构所有内容。如果您没有进行测试,这对我来说听起来有点危险。

        【讨论】:

          猜你喜欢
          • 2010-09-18
          • 2013-05-08
          • 1970-01-01
          • 2012-10-17
          • 2011-02-09
          • 2011-11-02
          • 2016-10-02
          • 2017-02-20
          • 1970-01-01
          相关资源
          最近更新 更多