java 好码
1【强制】不要在 foreach 循环里进行元素的 remove/add 操作。
remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。
正例:
List<String> list = new ArrayList<>();
list.add("1");list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (删除元素的条件) {
iterator.remove();
}
}
反例: for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}
2【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
正例:"test".equals(object);
反例:object.equals("test");
3 【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展
正例:
StringBuilder sb = new StringBuilder("start");
for (int i = 0; i < 100; i++) {
sb.append("hello");
}
String result = sb.toString();
这样可以避免在循环中创建过多的临时字符串对象,提高了性能和节省了内存。
如果是在多线程环境下进行字符串操作,可以考虑使用 StringBuffer
,它与 StringBuilder
类似,但是线程安全的。
总之,使用 StringBuilder
或 StringBuffer
的 append
方法来处理循环内的字符串连接可以提高性能、降低内存消耗。
4【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
正例:
public class TimerTaskThread extends Thread {
public TimerTaskThread() {
super.setName("TimerTaskThread");
...
}
}
5【参考】volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题, 但是如果多写,同样无法解决线程安全问题。如果是 count++操作,使用如下类实现: AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推 荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)。
【推荐】表达异常的分支时,少用 if-else 方式,这种方式可以改写成:
if (condition) {
... return obj;
}
// 接着写 else 的业务逻辑代码;
说明:如果非得使用 if()...else if()...else...方式表达逻辑,【强制】避免后续代码维 护困难,请勿超过 3 层。
正例:超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现,
其中卫语句示例如下:
public void today() {
if (isBusy()) {
System.out.println(“change time.”);
return;
}
if (isFree()) {
System.out.println(“go to travel.”);
return;
}
System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”);
return;
}
6【强制】注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x<1(能够 取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后 取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。
7. 【强制】获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime(); 说明:如果想获取更加精确的纳秒级时间值,使用 System.nanoTime()的方式。在 JDK8 中, 针对统计时间等场景,推荐使用 Instant 类。
8 你提到的情况是Java中String
类的split
方法的一个常见陷阱。split
方法用正则表达式作为分隔符来分割字符串,并返回一个字符串数组。但是,如果输入字符串的末尾有分隔符,那么根据split
方法的实现,这些末尾的空字符串可能不会被包含在结果数组中。
例如,你给出的代码:
javaCopy Code
String str = "a,b,c,,";
String[] ary = str.split(",");
System.out.println(ary.length);
输出的结果是3
,而不是预期的5
,因为split
方法默认会丢弃末尾的空字符串。如果你想要包含这些空字符串,你需要使用split
方法的另一个版本,它接受一个第二个参数,这个参数是一个整数,表示应该应用模式的次数。如果这个参数是负数,那么模式将会被应用尽可能多的次数,并且数组可以有任意长度,末尾的空字符串也会被包括在内。
修改后的代码如下:
javaCopy Code
String str = "a,b,c,,";
String[] ary = str.split(",", -1);
System.out.println(ary.length);
正例:
StringUtils.split(propertyName, ".")
//StringUtils.split 方法
?public static String[] split(String str, String separatorChars) {
? ? ? ? return splitWorker(str, separatorChars, -1, false);
? ? }
这时输出的结果将是5
,因为设置了-1
,split
方法会保留所有的分隔符后面的空字符串。
当使用split
方法时,如果你需要访问数组中特定的索引,确保先检查数组的长度,以避免IndexOutOfBoundsException
异常。例如:
javaCopy Code
if (ary.length > 3) {
String someValue = ary[3]; // 安全访问,因为已经检查了数组长度 } else { // 处理数组长度不足的情况
}
这样的检查可以确保即使数组没有你期望的那么多元素,你的代码也不会抛出异常。
9【推荐】setter 方法中,参数名称与类成员变量名称一致,this.成员名 = 参数名。在 getter/setter 方法中,不要增加业务逻辑,增加排查问题的难度。
反例:
public Integer getData() {
if (condition) {
return this.data + 100;
} else {
return this.data - 100;
}
}
10 在设计接口时,为了避免对已有代码造成影响,不应该修改已经在使用的接口的方法签名。这样可以保持向后兼容性,并确保接口调用方的代码不需要修改。
当一个接口过时时,添加@Deprecated
注解是一种良好的做法。通过@Deprecated
注解,我们可以明确地将过时的方法标记出来,并提供一些额外的信息,例如推荐使用的新接口或服务。
下面是一个示例:
javaCopy Code
public interface MyInterface {
/** * @deprecated This method is deprecated. Use the newMethod() instead. */ @Deprecated
void deprecatedMethod();
void newMethod();
}
在上述示例中,我们在deprecatedMethod()
方法上添加了@Deprecated
注解,并通过注释明确说明该方法已经过时,推荐使用newMethod()
方法作为替代。
通过这样的做法,我们能够清楚地向接口调用方传达关于过时方法的信息,并提供他们使用替代方法的建议。这样可以减少对接口调用方的影响,并帮助他们平稳地迁移到新的接口或服务上。
总结起来,确保遵循接口设计原则,尽量避免修改已有接口的方法签名,而对于过时的接口,使用@Deprecated
注解并提供相关信息是一种良好的做法。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!