从《无效的Java》到《高效的Java》

在不存在《Effective Java》的世界里,它就成了《Ineffective Java》。

我认为最近如果要使用Java进行开发,常常会使用像SpringBoot这样的框架来构建应用程序。
SpringBoot真的做得非常好。它提供了很多优秀的机制,如依赖注入、自动配置等,可以减少代码的编写量。

熟悉Java的程序员通常会作为架构师来设计和实现框架。使用诸如模板方法模式等,构建易于批量生产的架构。然后将接口交给负责实现各功能的程序员,通过遵循框架来创建界面和业务处理。

然而,业务处理是当然必要的。在大家的工作现场中,关于如此大量且并行编写的代码的质量是怎样的呢?
我周围也存在这方面的问题,我认为在开发工作中需要有正确意识的工程师,因此我们开始为公司内部进行Java教育。本文总结了我在这个教育过程中通过代码审查发现的“原来是不理解这个啊”的问题。希望通过教育和审查,让管理者们在发现错误时不再常见的抱怨“为什么写这么烂的代码?”而是意识到教育和审查的重要性。也许,这样的工作环境中没有Effective Java/Readable Code等书籍,是否被尘封起来了呢?教育非常重要。

Java教育是什么样的?

举办了两个季度。

    • 2018年6月-9月 26名 週1回 全16回

 

    2018年11月-2019年2月 15名 週1回 全8回

每周我们会有两小时的讲义,并且会布置练习题,通过Pull Request收到后,我会进行审查并返回意见。在课程期间,我们会通过Slack进行跟进。教材我购买了Kasareal老师的教材进行实施。虽然比一般的书籍要贵一些,但是教程的顺序很好,很容易理解。如果一直处于可以进行结对编程等环境的话,可能就不需要教材了。不过,我对于这次内部教育非常满意,觉得很顺利。

这些人是谁

    • Javaを業務で書き始めた1年目

 

    • 実はJavaを書いているけどという3-4年目ぐらい

 

    別の言語からJavaに転向してきた10年目など様々です。

以下是我在Pull Request中看到的一些你应该知道的内容的总结。排名是根据我的感觉。
如果你对某些内容说”这个肯定知道啦”,请一定要问问你周围的新手。你周围可能也有很多人不知道这些。不学的东西就不会知道。

无效的Java

「项目1中的toString()是什么意思?」

很多人不知道这个方法的作用,让我感到惊讶。
你有没有见过写着object.getXXX() + object.getYYY()的代码,尽管toString()方法已经在对象中实现了?

请问您的周围的年轻人也有没有遇到不了解toString()方法含义的情况?

項目2 声明左边的类型始终与右边的类型相同。

ArrayList<String> list = new ArrayList<>();

当然,左侧应该是List。但是,如果没有考虑接口和多态等概念,左侧会被声明为与右侧相同的类型。
对于处于这种状态的人来说,即使说OCP之类的东西,也会变得一头雾水,所以需要按照继承->接口->集合->多态的顺序逐步解释。
仅凭这一点,就能正确思考并定义左侧。

将项目3转换为说唱歌手

Long.valueOf(Files.size(pathA)).equals(Long.valueOf(Files.size(pathB)));

你可能是从某个地方复制过来的。或者,将其转化成饶舌歌手可能会带来一种安心感。正确理解如何处理原始数据是必要的。
通过理解这一点,你将逐渐学会避免创建无用的对象。

第四项,不必要的评论不需要。

你肯定见过这样的代码吧。Eclipse自动生成的注释仍然保留着,像变量的说明等等没什么用的注释。前者是因为写代码过于专注,注释根本没注意到。后者则是接受了注释很重要的教育,但注释却被忽略并被遗弃的例子吧。

如果你在进行配对编程等活动时,可以立刻意识到这一点,但如果不是这种情况,那么就没有人会学到,这种情况会一直持续下去。应该正确地教导他们。基本上,不需要评论。如果在工作中进行非正常操作时,可能是必要的。否则,在后续的维护阶段可能会因为评论而出现错误。

这个项目不需要这个 if 语句。

public boolean isLessThan1KB(String file) throws Exception {  
        // Pathオブジェクト生成  
        Path path = Paths.get(file);  
        if (Files.size(path) < 1024) {  
            return true;  
        } else {  
            return false;  
        }  
    }

这是非常常见的写法。如果条件满足,则可以使用return Files.size(path)<1024来替换后面的if语句。
当将代码视为只要工作就好时,很多人会使用这种写法。如果觉得这种写法有些冗长,那就需要上级进行代码审查。

为什么不看返回值的原因是什么?

    public void delLine(String line) { 
        lines.remove(lines.indexOf(line)); 
    }

List 的 remove 方法具有返回值。有时会看到忽略返回值直接使用的情况。这可能是因为在网络上有类似的写法。

其中的原因很大程度上是初学者不擅长错误处理。一旦理解了异常、错误处理等方面的知识,这个问题自然会解决。

第七项目不熟悉try-with-resources操作。

仍有很多人认为现场的JDK仍然是6版本。他们还要使用过时的写法到什么时候呢?不管是twr、for循环、Stream、lambda等,所有这些都是相同的处境。
我建议重新认真学习Java8。对于从Java11开始的新人来说,这些人只是威胁而已。

项目8 喜欢嵌套

if(xxx == true) {
 //処理
} else {
 //処理
}

一定会以这样的方式写作的认真的程序员。我想提醒他们世界上有一种叫做“守卫子句”的东西。使用守卫子句会使事情更加清晰明了。这是因为经常陷入嵌套代码的困扰。我知道一次减少一个嵌套可能看不出太大差别,但是如果进行仔细审查,他们会很快理解并享受到它的实际效果。

我不理解equals()方法的含义。

这个本来就非常困难。即使是Java的中级开发者,被要求即时解释可能也会觉得困难。但是,如果不理解这个,我会感到害怕,也无法使用TreeMap等。因为我不知道任何对象是否被正确排序。所以,我总是成为HashMap的使用者,在调用get()之后进行琢磨。实现equals()就自然要实现hashCode()。否则会发生很多奇怪的现象。只有真正理解了这一点,代码才能变得更加优雅。这正是Effective Java的精髓。

项目10 不可变的?

我不知道不可变对象。这是从初级到中级升级所需的非常重要的知识。有能力推断对象状态以消除潜在的错误。这就是一个Java中级开发者所需的能力。如何创建不可变对象?它在什么情况下使用?如果理解了这些,类的设计空间将大大扩展。相反,如果不了解这些,将只能一味地进行平庸的设计。

此外,虽然与不可变性没有直接关联,但对于类似于 final List stringList; 这样的 List,有些人可能无法正确解释 final 的含义,因此正确理解也非常重要。

从《无效的Java》到《有效的Java》的世界

初学者可以通过阅读《Effective Java》来提升自己,因为这本书中有许多初级到中级的过渡内容。初学者可以向中级者请教一些他们不懂的问题。中级者可以邀请初学者一起参加读书会讨论。《Effective Java》第三版

如果你想重新学习Java8,这里是一个推荐的选择。
作为一名Java程序员,掌握Java SE 8的实践编程是必备的。

广告
将在 10 秒后关闭
bannerAds