原文
Best coding practices every java developer should follow
引言
把标题翻译成中文在国内也是一个老生常谈的问题:编程习惯和编码规范。
这篇文章大部分观点和国内的规范习惯类似,令我好奇的是外国人是如何理解这些内容的?
注意本文的Tips排序是打乱的,个人把感兴趣放到了前面来了。这篇文章的评论区非常精彩,这里一并整合了评论区的读者观点。
不管是学习老外的思考方式,或是在评论区当中看读者的讨论和纠正错误,阅读本文都是值得推荐的。
抱着半信半疑的态度学习这些内容,你会得到比单纯的了解和接受建议更多的收获。
4. 尽可能让变量私有化
如果变量不需要意对外访问,那就建议使用私有描述对于参数进行描述。
评论区的读者对于这一个小节做了补充:
- 如果是dto并且是final的,拥有公用数据的时候可以不私有化.。
- 比大量的setter更好建议是更合理的利用设计模式构建对象(比如建造者),或者利用委托第三方对象生产合适的对象(静态工厂替代构造器)。
- 尽可能让对象不可变。
6. 警惕冗余初始化
Therefore, a java best practice is to be aware of the default initialization values of member variables and avoid initializing the variables explicitly.
Java 最佳实践是了解成员变量的默认初始化值并避免显式初始化变量,Java语言很多变量存在默认值,在自己编写初始化的时候不建议使用Java的默认值。
另一方面,有时候可以利用Java的初始化做数据库字段的优化,比如开关状态建议把0设置为开放1设置为关闭。
下面的代码的的对象初始化代码是毫无意义的:
public class Person { private String name; private int age; private boolean; public Person() { String name = null; int age = 0; boolean isGenius = false; } }
Although it is very common practice, it is not encouraged to initialize member variables with the values: like 0, false and null. These values are already the default initialization values of member variables in Java. Therefore, a java best practice is to be aware of the default initialization values of member variables and avoid initializing the variables explicitly.
尽管这是非常常见的做法,但不鼓励使用以下值初始化成员变量:如 0、false 和 null。这些值已经是 Java 中成员变量的默认初始化值。因此,Java 最佳实践是了解成员变量的缺省初始化值,并避免显式初始化变量。
See more here: Java default Initialization of Instance Variables and Initialization Blocks。
5. Stringbuilder 替换字符串拼接【争议】
实际上多数情况下“大可不必”,只有for循环的情况才考虑是否使用Stringbuilder替换。日常情况下字符拼接操作是完全没有问问题的,javac编译之后会把字符串自动用StringBuilder替换,真正应该手动创建该对象的场景是在for循环当中的大量的字符串拼接,内部会每次迭代新建Stringbuilder。
随着JDK版本的升级,到JDK9版本for循环新建StringBuilder的情况已经被改善了(但个人未从OpenJDK中找到对应源码验证)。
JDK13 从Python那边把多行文本的语法搬过来了,定义多行文本可以类似下面这样:
String htmlContent = “““<html> <head> </head> <body> <p>Hello world!</p> </body> </html>""";
最后需要注意的是使用Stringbuilder,仅仅应该用在多线程循环操作字符串当中,如果在同步方法里面效率会非常低并且很慢。
介绍
As a general rule, optimize at an architectural level, and write code for readability. Later on it’s easier to optimize a neat function, than to look for bugs in an optimized one.
上面意思大致是说通用规则是优先写出具备高可读性的代码,然后再去进行优化这些简单的可优化点,这比在优化代码找错误要简单很多。
15. dry和kiss
DRY stands for “Don’s Repeat Yourself
如果代码可以公用就尽量公用,不要复制粘贴代码。
kiss:KISS stands for “Keep It Simple, Stupid”.
KISS就是保持简单,愚蠢。这个愚蠢指的是方法最好只知道干一件事情。这两点和Unix最初的设计的理念是一样的,简单好用即是美。
14. Solid
Single Responsibility Principle 单一职责:每个类和接口有明确目标。
Open-Closed Principle 开闭原则:开放扩展,封闭修改。
Liskov Substitution Principle 里式替代:尽可能让代码多态。
Interface Segregation Principle 接口隔离:实现接口替代类继承。
Dependency Inversion Principle 依赖倒转原则:依赖抽象而不是依赖实现。
7. 尽可能使用增强for循环或者foreach
建议使用增强for循环(JDK5)和JDK8的foreach,当然最好的建议是活学活用stream的API。为什么会有这样的建议?好像for-index也不是啥坏写法。
It’s because the index variable is error-prone, as we may alter it incidentally in the loop’s body, or we may starts the index from 1 instead of 0.
这是因为索引变量容易出错,因为我们可能会在循环的主体中偶然改变它,或者我们可能从1而不是0开始索引。下面是Stream API带来便利的简单例子:
public Integer findSmallesPositiveNumber(List<Integer> numbers) { Integer smallestPositiveNumber= null; for (Integer number: numbers) { if (number > 0) { if (smallestPositiveNumber == null || number < smallestPositiveNumber) { smallestPositiveNumber = number; } } return smallestPositiveNumber; }
使用Stream APi精简之后:
public Optional<Integer> findSmallesPositiveNumber( List<Integer> numbers) { return numbers.stream() .filter(number -> number > 0) .min(Integer::compare); }
13. 日志打印规则
作者的下面几条规则有待商榷,我个人建议是避免下面的做法:
Developer should add logger on method entry and exit.
在进出重要方法打印入参和出参。
谨慎使用,建议涉及金额的操作情况打印。
Developer should add logger in “if” and “else” case to track which condition is true in case of any error.
在if和else的条件判断处打印参数。
Developer should also log exception to track the issue
对于异常信息必须打印。
更为合理的做法是像下面这样:
Definitely don’t log every if-else statement!
不要在if/else分支中打印,更为合理的建议是记录响应以及错误。
Don’t log every method entry and exit!
不要在每个方法的入参和出参打印。当然这并不是铁律,比如三方接口调用就必须要在“入口”和“出口”中打印以便快速定位问题和甩锅。
**Log exceptions that are unexpected. **
记录“意外”的异常。比如多线程有可能的interrupt处理,文件读写有可能的IO异常。
从褒义和贬义两个层面看,日志都是非常具备“价值”的,好的日志可以帮你快速定位问题,不好的日志就像是垃圾一样迅速占用服务器的磁盘。只有非常核心的日志才需要跟踪每一步的行为,绝大多数情况下日志只需要在影响业务的位置进行打印。在打印日志段时候多思考一下日志等级的选择,这意味着你生产能否快速定位问题。
12. Hardcoding硬编码
硬编码回会导致程序难以理解。使用硬编码会增加理解难度,通常使用枚举替代是不错建议。根据dry的原则,在定义硬编码的时候,如果魔法值在JDK中存在类似定义或者存在现实意义,应该果断通过下面的方式进行纠正,比如下面的例子:
private int storeClosureDay = 7;
应该被替换为下面这样:
private static final int SUNDAY = 7; […] private int storeClosureDay = SUNDAY;
不要这样使用,更为合适的处理方式是使用DayOfWeek 的API:
private DayOfWeek storeClosureDay = DayOfWeek.SUNDAY;
避免硬编码是非常好的编程习惯,更好的习惯是使用易懂的硬编码。
11. 注释
关键:注释只有在可读性较差并且需要注释描述关键意图的时候才使用。
As your code will be read by various people with varying knowledge of Java, Proper comments should be used to give overviews of your code and provide additional information that cannot be perceived from the code itself. Comments are supposed to describe the working of your code to be read by Quality assurance engineer, reviewer, or maintenance staff .
由于代码将被具有不同 Java 知识的各种人阅读,因此应该使用适当的注释来概述代码,并提供无法从代码本身感知的其他信息。注释应该描述代码的工作方式,以供质量保证工程师、审阅者或维护人员阅读。
注释关键点应该具备可读性,有时候没有任何注释的代码确实让人痛苦,更可怕的是因为代码更新但是注释不更新,这样的事情也时有发生=-=。最好的注释应该是代码本身会告知作者意图。
PS:个人看过的没啥注释也能完全看懂,并且看完觉得写的非常美的代码目前只有Redission和Spring。
10. 避免创建不必要对象
对象创建是最消耗内存的操作之一,这就是为什么最好的 Java 实践是避免创建任何不必要的对象,并且只应在需要时创建它们。
【Java】Best coding practices every java developer should(二)https://developer.aliyun.com/article/1395276