将中型代码库从 Java 1.4.2 迁移到 Java 5 的策略

发布于 2024-07-16 02:16:07 字数 756 浏览 3 评论 0原文

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

我的问题:

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

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

如有任何建议,我们将不胜感激 - 提前致谢。

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

感谢您的所有评论 - 很多很棒的观点。 在软件开发人员的生活中,总会有一些项目你努力完成,但由于一些更“紧急”的事情而从未抽出时间来完成。

关于Java 5的使用(当时),这是客户端生产环境所需要的,所以这就是为什么我们没有使用Java 6。

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

再次感谢所有对此主题做出贡献的人,并对迟到的后续行动表示歉意。

I'm in the process of reviewing a code base (~20K LOC) and trying to determine how to migrating it from 1.4.2 to 5. Obviously, it's not an overnight project and the suggestion which I have received is to write new code against Java 5 and migrate the old code in a piece-meal fashion. Also, I'm no expert in the new features in Java 5 (i.e. I know of them, but have never written any for production use).

My questions:

  1. What features of Java 5 are typically used in production code? (i.e. generics, auto-boxing, etc.) Are there features to be avoided / not considered to be best-practices?

  2. What are the best refactoring strategies which I can use migrate a code base of this size? (i.e. make changes to classes one at a time only when a class is edited, etc.) Objective - reduce risk on the code base. Limitation - resources to do refactoring.

Any advice is appreciated - thanks in advance.

UPDATE - a year too late, but better late than never? =)

Thank you for all of the comments - lots of great points of view. In the life of a software developer, there's always going to be the projects you strive to finish but never get around to because of something more "urgent".

With respect to the use of Java 5 (at that time), it was something which was required in the client's production environment, so that was why we did not use Java 6.

I found that the stronger typing for collections, enums and unboxing of primitives were the features I tend to apply the most, both to old and new code. The refactoring was fairly straight-forward, but code comprehension improved significantly and standards became easier to enforce. The ones I had the most trouble with was the generics; I think it's a concept which I still haven't had a chance to fully grasp and appreciate yet, so it was difficult for me to find previous cases where the application of generics was appropriate.

Thanks again to everyone who contributed to this thread and apologies for the late follow up.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

活泼老夫 2024-07-23 02:16:07

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 功能,除非您已经出于其他原因更改了代码。

Java 5 is almost completely backwards compatible with Java 4. Typically, the only change you must make when you migrate is to rename any usages of the new enum keyword in the Java 4 code.

The full list of potential compatibility problems is listed here:

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

The only other one that I've run into in practice is related to the change in the JAXP implementation. In our case, it simply meant removing xerces.jar from the classpath.

As far as refactoring goes, I think that migrating your collection classes to use the new strongly-typed generic versions and removing unnecessary casting is a good idea. But as another poster pointed out, changing to generic collections tends to work best if you work in vertical slices. Otherwise, you end up having to add casting to the code to make the generic types compatible with the non-generic types.

Another feature I like to use when I'm migrating code is the @Override annotation. It helps to catch inheritance problems when you're refactoring code.

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

The new concurrency library is very useful if your code uses threading. For example, you may be able to replace home-grown thread pools with a ThreadPoolExecutor.

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

I would definitely take the approach of updating the code as you change it during normal maintenance. Other than the compatibility issues, I don't think there is a compelling reason to use the new Java 5 features unless you're already changing the code for other reasons.

妄司 2024-07-23 02:16:07

仿制药的“病毒式”本质存在一个非常现实的问题: 一旦您开始在架构中的给定层引入它们,您通常希望在上一层和下一层引入它们。 下面也是如此。 我发现引入泛型可能最好在完全“垂直”的情况下完成。 但您不必一次完成所有垂直领域的工作。

There is one very real issue with the "viral" nature of generics; once you start introducing them at a given layer in an architecture you generally want to introduce it at the layer above & below as well. I have found that introducing generics is probably best done in full "verticals". But you do not have to do all the verticals at once.

提赋 2024-07-23 02:16:07

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

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

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

要做的另一件事是尝试在 Java 6 下启动您的应用程序,看看会出现什么问题。 情况可能比你预想的还要糟糕。 可能会好很多。

您可能需要注意的另一件事是,根据它的声音,您的应用程序中将有一些已被弃用的罐子/库。 有些甚至可能与 1.4.2 以上的 Java 不兼容。 您可能还想将所有这些升级到最新版本。

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

但也有例外,升级可能会产生深远的影响。 我想到的是 Axis1 到 Axis2。 这些情况需要更仔细的思考。

至于使用什么功能……几乎全部都有。 我想不出任何应该避免的事情。

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

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

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

This is a really hard question to answer because it depends on what code will be affected and how critical that code is.

First and foremost, when migration is a nontrivial undertaking, do yourself a favour and upgrade to the latest version of Java, which would be Java 6 not Java 5. Java 6 has been out for a year and a half or more and is mature. There's no reason to not pick it over Java 5 (imho).

Secondly, like any software project, your goal should be to get something into production as soon as you possibly can. So you need to identify a slice of your system. The smaller the better, the more non-cdritical, the better.

The other thing to do is just try starting up your app under Java 6 and seeing what breaks. It might be worse than you expected. It might be much better.

The other thing you'll probably need to be aware of is that by the sounds of it you will have jars/libraries in your app that have since been deprecated. Some may not even be compatible with Java beyond 1.4.2. You will probably want to upgrade all of these to the latest version as well.

This will probably mean more stuff breaking but using old/deprecated APIs is just kicking the can down the street and causes you other problems.

There are exceptions to this where upgrading can have far-reaching consequences. Axis1 to Axis2 comes to mind. Those situations require more careful thought.

As for what features are used... all of them pretty much. I can't think of any that should be avoided off the top of my head.

Also, I just noticed the size of your project: ~20K LOC. That's actually quite small (eg I've written an app about that size in the last 3 months by myself).

Lastly, this also depends on how easily you will find things that break. If you have good unit test coverage then great. That's pretty rare though. If you can just run through the app and reliably find problems it's not too bad.

The problematic situations are where scenarios are hard to test and it's likely you won't uncover problems straight away. That calls for more caution.

手心的温暖 2024-07-23 02:16:07

您可能希望迁移在从 1.4 到 5 的过渡过程中不起作用的内容(不确定会是什么),但我会因此而迁移内容。

如果您确实选择了这条路线,那么有一些问题:

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

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

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

You would want to migrate stuff that doesn't work in the transition from 1.4 to 5 (not sure what that would be), but I'd be wary of migrating stuff for the sake of it.

If you do take this route, some questions:

Do you have comprehensive test coverage ? If not, you should write unit tests for the code you're going to be migrating.

Do you have components that are widely used within your codebase ? If so, they are probably candidates to be migrated in terms of their API (e.g. using generics etc.)

In terms of what's widely used from Java 5. Generics is important and makes your life a lot easier. I don't see autoboxing too much, nor enums (this is all relative). Varargs almost never. Annotations are useful for frameworks, but I consume these. I don't think I've ever implemented one myself.

你的背包 2024-07-23 02:16:07

20(非注释)kloc 应该足够小,可以大爆炸地插入泛型。 显然,首先要确保您的代码可以在 Java SE 5 上编译并运行。 关于泛型相对简单的事情是添加它们对语义的改变很小(某些重载可能会因为隐式情况而改变 - Iteratoriter; ... System.out.println(iter.next ()); 作为我脑海中的一个坏例子)。

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

增强型和自动装箱之类的东西非常本地化,可以零碎添加。 枚举比较少见,可能需要考虑一下您实际上将如何使用它们。

20 (non-comment) kloc should be small enough to insert generics with a big bang. Obviously make sure your code compiles an runs on Java SE 5 first. The relatively easy thing about generics is that adding them makes very little change to semantics (certain overloadings can change because of implicit cases - Iterator<char[]> iter; ... System.out.println(iter.next()); as a bad example off the top of my head).

Some cases adding generics will highlight conceptual problems with the code. Using one Map as two maps with disjoint key sets, for example. TreeMap is an example in the Java library where a single class has two distinct mode (using Comparator<T> or Comparable<T>).

Things like enhanced-for and auto-boxing are very local and can be added piecemeal. enums are rarer and might take some thinking about how you are actually going to use them.

终陌 2024-07-23 02:16:07

我认为你处理这个问题的方式是错误的。 您的计划不应该是将所有当前代码更新到 Java 1.5,您的计划应该是确保所有当前代码在 1.5 中运行与在 1.4.2 中完全相同,并且所有将来编写的代码都可以在 1.5 中正常运行。

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

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

I think you're going about this the wrong way. Your plan shouldn't be to update all current code to Java 1.5, your plan should be to ensure that all current code runs exactly the same in 1.5 as it did in 1.4.2, and that all future code written will work fine in 1.5.

I've gone through a few transitions like this of varied sized code bases. The goal was always to make sure we had a ton of unit tests so that we could easily plug in 1.5 and run our tests through it. We actually encountered about 10 problems, mostly related to regular expression libraries not supporting something or supporting something differently.

Write all new code in 1.5 then, and if you change an older class for whatever reason, spend a minute and implement generics, but there's no reason to refactor everything. That sounds a bit dangerous to me if you don't have the tests in place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文