“如果你一直拖着过去不放,就无法向前进步。”这正是我在代码审查时对团队说的话。然而,每次我打开一个拉取请求时,我仍然看到过时的Java特性、坏习惯和应该在几年前就被淘汰的编码习惯。所以,如果你今天在使用Java,无论你是初级、中级还是高级开发者,这篇文章都适合你 🫵 。其中一些观点可能会让你感到不舒服。有些可能与你所学的相违背。但这正是你应该读到最后的原因。
## 1. 错误使用 Optional.get()
Optional是一个很棒的特性,但我看到许多开发者误用了它:
“`java
Optional<String> value = getValue();
String result = value.get(); // 可能抛出 NoSuchElementException!
“`
**这是错误的!**
如果你在使用**_Optional_**,就要拥抱它的API:
“`java
String result = value.orElse(“default”);
// 或者
value.ifPresent(val -> System.out.println(val));
// 或者
String result = value.orElseThrow(() -> new IllegalArgumentException(“Value missing”));
“`
## 2. 硬编码值而不是使用常量
**_这是我在代码中看到的最大罪过之一:_**
“`java
if (status == 3) {
// do something
}
“`
一个新的初级开发者加入团队,他不知道 **3** 是什么意思。然后他错误地修改了逻辑。**砰。生产环境出现了bug。**
正确的方式:
“`java
// 使用 static final
public static final int STATUS_COMPLETED = 3;
if (status == STATUS_COMPLETED) {
// do something
}
// 更好的方式 – 使用枚举:
if (status == Status.COMPLETED) {
// do something
}
“`
**为什么?** 因为这样你的代码变得自文档化且安全。
## 3. 有缺陷的单例模式的双重检查锁定
**_经典错误:_**
“`java
public class MyClass {
privatestaticMyClassinstance;
privateMyClass(){
// 私有构造函数来强制单例模式
}
publicstaticMyClassgetInstance(){
if (instance == null) {
synchronized(MyClass.class) {
if (instance == null) {
instance = new MyClass();
}
}
}
return instance;
}
}
“`
除非使用`volatile`完美地完成,否则这在Java中是有缺陷的。在并发环境中可能出现微妙的错误。
**这里是修复方法:**
“`java
public class MyClass {
privatestaticvolatileMyClassinstance;// <<< 修复:添加 ‘volatile’
privateMyClass(){
// 私有构造函数来强制单例模式
}
publicstaticMyClassgetInstance(){
if (instance == null) {
synchronized(MyClass.class) {
if (instance == null) {
instance = new MyClass();
}
}
}
return instance;
}
}
“`
**_更好的方式:_**
“`java
// 使用枚举单例:
public enum Singleton {
INSTANCE;
publicvoiddoSomething(){
// 实现
}
}
// 或者使用 static final:
public class MySingleton {
publicstaticfinalMySingletonINSTANCE=newMySingleton();
}
“`
这些方式安全、简单,并且避免了并发错误。
## 4. Vector 和 Hashtable
现在是2025年。然而,有时我仍然看到这样的代码:
“`java
Vector<String> vector = new Vector<>();
Hashtable<String, String> table = new Hashtable<>();
“`
`Vector`和`Hashtable`都是Java早期的**遗留类**。它们是**同步的**,因此比现代替代方案**慢得多**。
**应该使用什么替代:**
“`java
// 对于List:
List<String> list = new ArrayList<>();
// 对于Map:
Map<String, String> map = new HashMap<>();
“`
如果你需要**线程安全**,使用:
“`java
List<String> list = Collections.synchronizedList(new ArrayList<>());
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
// 或者更好的:
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
“`
**为什么要停止使用`Vector`和`Hashtable`?**
* 在现代应用中性能差
* 存在更好的替代方案,对同步有更精细的控制
## 5. 原始类型
我仍然审查到这样的PR:
“`java
List list = new ArrayList();
list.add(“Hello”);
list.add(123); // 什么?在字符串列表中放整数?
“`
这是危险的💀。
原始类型移除了类型安全性,导致在运行时爆发的微妙错误。
**正确的方式:**
“`java
List<String> list = new ArrayList<>();
list.add(“Hello”);
// list.add(123); // 编译错误 – 很好!
“`
**提示:** 总是使用**泛型**。你的IDE会帮你早期发现错误。
## 6. StringBuffer(当你不需要同步时)
许多开发者使用这个:
“`java
StringBuffer sb = new StringBuffer();
sb.append(“Hello “);
sb.append(“World”);
“`
但除非你在做**多线程工作**,否则`StringBuffer`是不必要的慢。
**应该使用什么替代:**
“`java
StringBuilder sb = new StringBuilder();
sb.append(“Hello “);
sb.append(“World”);
“`
`StringBuilder`更快,对于单线程操作来说已经足够了,这是**你大部分代码**的情况。
## 7. 直接使用 SimpleDateFormat
这是连高级开发者都会犯的经典错误:
“`java
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);
String date = sdf.format(new Date());
“`
问题在哪里?🤔 `SimpleDateFormat`是**不线程安全的**。如果这段代码在Web应用或多线程环境中运行,它可能抛出**奇怪的日期格式化错误**。
**应该使用什么替代:**
“`java
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(“yyyy-MM-dd”);
String date = LocalDate.now().format(formatter);
“`
新的`java.time`包(从Java 8开始)是**线程安全的**,并且远远优越。
## 8. 使用 System.out.println 进行日志记录
我实际上见过企业应用程序中有数百个**`System.out.println()`**语句。\
当你调试生产问题时,你会后悔的。
**正确的方式:**
使用日志框架,如**SLF4J with Logback**或**Log4j2**:
“`java
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
logger.info(“Processing order: {}”, orderId);
logger.error(“Error processing payment”, ex);
“`
* 你可以获得日志级别(info、debug、error)
* 你可以将日志重定向到文件
* 你可以控制日志格式和保留期
**🙅♂️永远不要在生产代码中部署`System.out.println`**
## 9. 过度使用同步而不是使用现代并发
许多开发者仍然这样做:
“`java
synchronized(this) {
// do something
}
“`
但Java已经发展了🪴。`java.util.concurrent`提供了强大、更安全、性能更好的工具:
* 使用**ReentrantLock**进行显式锁定
* 使用**ConcurrentHashMap**而不是同步映射
* 使用**AtomicInteger**、**AtomicBoolean**等
* 使用**ExecutorService**而不是手动管理线程
**除非绝对必要,否则避免使用synchronized。**并发很难——让现代库来帮助你。
## 10. 过时的集合API方法
我有时仍然看到这样的代码:
“`java
Enumeration<String> e = myVector.elements();
while (e.hasMoreElements()) {
System.out.println(e.nextElement());
}
“`
❌ 当你可以使用现代for-each循环时,停止使用`Enumeration`和`Iterator`:
“`java
for (String item : myList) {
System.out.println(item);
}
// 或者更好的 – 使用流:
myList.forEach(System.out::println);
“`
这些更清洁、现代、更可读。
没有回复内容