如果你也是從 public static void main(String[] args) 和 System.out.println() 開始Java生涯的,那也是Java老油條了。在日常的業務開發中,我們每天都在寫着增刪改查的邏輯,有時候會覺得Java有點笨重,語法有點囉嗦。
但其實,Java在不斷進化。從我們熟悉的Java 8到現在的Java 25,它多了很多實用的新特性和一些不為人知的老技巧。用好它們,不僅能讓代碼更簡潔,還能在同事面前小小地秀一下。
下面就聊幾個我自己在工作中覺得特別好用的技巧,看看你用過幾個。
用枚舉(Enum)乾點正事
很多人對枚舉的印象還停留在定義一組常量,比如 MALE, FEMALE。但其實,枚舉遠比這強大,它甚至可以擁有自己的方法和實現,非常適合用來替代一堆 if-else 或者 switch 的策略邏輯。
舉個例子,假設我們有不同的會員等級,需要計算折扣後的價格:
// 利用枚舉實現不同會員的折扣策略
public enum MemberType {
REGULAR {
@Override
public double applyDiscount(double price) {
return price * 0.98; // 普通會員98折
}
},
VIP {
@Override
public double applyDiscount(double price) {
return price * 0.9; // VIP會員9折
}
},
PREMIUM {
@Override
public double applyDiscount(double price) {
return price * 0.8; // 高級會員8折
}
};
public abstract double applyDiscount(double price);
}
// 使用起來非常清晰
public class PriceCalculator {
public static void main(String[] args) {
double originalPrice = 100.0;
double vipPrice = MemberType.VIP.applyDiscount(originalPrice);
System.out.println("VIP會員價:" + vipPrice); // 輸出:VIP會員價:90.0
}
}
這樣寫,每種會員的折扣邏輯都封裝在自己的枚舉實例裏,代碼清晰,擴展起來也方便。以後要加新的會員等級,只需要添加一個新的枚舉實例就行,完全符合開閉原則。
用記錄(Record)告別樣板代碼
自從Java 16引入了 Record 類型,我寫DTO(數據傳輸對象)的幸福感直線上升。以前為了定義一個簡單的數據載體,得手動寫一堆的 getter, setter, equals(), hashCode() 和 toString(),或者依賴Lombok。
現在,一行代碼就夠了。
// 以前的寫法
// public class User {
// private final String username;
// private final String email;
// // ... 一大堆 getter, equals, hashCode, toString ...
// }
// 現在用Record
public record UserProfile(String username, String email) {}
// 使用
public class Main {
public static void main(String[] args) {
UserProfile user = new UserProfile("dev_user", "user@example.com");
System.out.println(user.username()); // 直接調用,像方法一樣
System.out.println(user); // 自帶了很好的toString()實現
}
}
編譯器會自動幫你生成所有必需的方法,代碼瞬間清爽了很多。
類型安全的ID,防止傳錯參數
在業務代碼裏,經常會用 Long 或者 String 來表示各種ID,比如 userId, orderId, productId。這樣做的風險是,方法的參數很容易傳混。
// 很容易寫錯的調用
public void processOrder(Long userId, Long orderId) {
// ...
}
// 調用時可能不小心把兩個ID搞反
processOrder(orderId, userId); // 編譯器不會報錯,但邏輯全錯了
那就可以利用 Record (或者普通類) 來給ID一層包裝,增加類型安全性,讓編譯器在編碼階段就幫我們發現錯誤。
public record UserId(long value) {}
public record OrderId(long value) {}
public class OrderService {
public void processOrder(UserId userId, OrderId orderId) {
System.out.println("處理用户 " + userId.value() + " 的訂單 " + orderId.value());
}
public static void main(String[] args) {
OrderService service = new OrderService();
UserId userId = new UserId(1001L);
OrderId orderId = new OrderId(9527L);
service.processOrder(userId, orderId); // 正確
// service.processOrder(orderId, userId); // 這行代碼會直接編譯失敗,安全!
}
}
這個小改動能避免很多難以排查的線上問題。
用 Stream API 告別 for 循環
從Java 8開始,Stream API 就已經是處理集合的標配了。如果還在用 for 循環和一堆 if 來做篩選和轉換,那代碼讀起來會很費勁。Stream API可以用一種更聲明式、更流暢的方式來操作數據。
比如,我們要從一堆產品裏,篩選出價格大於500的,然後取出它們的名字:
import java.util.List;
import java.util.stream.Collectors;
public class StreamDemo {
record Product(String name, double price) {}
public static void main(String[] args) {
List<Product> products = List.of(
new Product("筆記本電腦", 5999.0),
new Product("鼠標", 299.0),
new Product("機械鍵盤", 799.0)
);
// 使用Stream API
List<String> expensiveProductNames = products.stream()
.filter(p -> p.price() > 500.0) // 篩選價格
.map(Product::name) // 提取名稱
.collect(Collectors.toList()); // 收集成列表
System.out.println(expensiveProductNames); // 輸出: [筆記本電腦, 機械鍵盤]
}
}
鏈式調用,一氣呵成,代碼的意圖一目瞭然。
用文本塊(Text Blocks)優雅地寫多行字符串
以前在Java代碼裏拼接SQL或者JSON字符串,簡直是一場災難,充滿了 + 號和 \n 轉義符,可讀性極差。Java 15引入的文本塊(Text Blocks)徹底解決了這個問題。
看看對比:
public class TextBlockDemo {
public static void main(String[] args) {
// 以前的方式,又醜又容易出錯
String oldJson = "{\n" +
" "name": "Alice",\n" +
" "age": 30\n" +
"}";
// 現在用文本塊,所見即所得
String newJson = """
{
"name": "Alice",
"age": 30
}
""";
System.out.println(oldJson.equals(newJson)); // 輸出: true
}
}
用三個雙引號 """ 包起來,字符串的格式就能完全保留,代碼乾淨多了。
還在用 != null?試試 Optional
空指針異常(NullPointerException)應該不少 Java 開發者都很熟了。為了避免它,我們代碼裏堆滿了 if (obj != null) 的判斷。Optional 的出現就是為了更優雅地處理可能為空的情況。
import java.util.Optional;
public class UserRepository {
// 模擬從數據庫查找用户
public Optional<String> findUserNameById(long id) {
if (id == 1L) {
return Optional.of("Alice");
}
return Optional.empty(); // 表示沒找到
}
public static void main(String[] args) {
UserRepository repo = new UserRepository();
// 優雅地處理
repo.findUserNameById(1L)
.ifPresentOrElse(
name -> System.out.println("找到用户:" + name),
() -> System.out.println("用户不存在")
);
// 獲取值,如果不存在則提供一個默認值
String userName = repo.findUserNameById(2L).orElse("默認用户");
System.out.println("查詢ID為2的用户:" + userName);
}
}
用 Optional 不僅能讓代碼意圖更明確(這個方法的返回值可能為空),還能通過鏈式調用寫出更流暢的代碼。
管理好Java環境,才能玩轉新特性
看到這裏,你可能已經注意到,上面提到的不少特性都和Java版本有關。比如 Record 是Java 16的,文本塊是Java 15的,ifPresentOrElse 是Java 9的。在實際工作中,我們經常會遇到這樣的情況:
- 老項目A還在用穩定的Java 8。
- 新項目B想嘗試Java 17的LTS版本。
- 自己想學習一下最新的Java 25。
在電腦上同時管理這麼多Java版本,配置環境變量,為不同項目切換JDK,挺讓人破防的。每次切換環境,都要敲一堆命令,或者在IDE裏改來改去,很影響開發效率。
所以,這時候就需要ServBay。
它本來是一個集成了PHP、Node.js等環境的Web開發工具,但我發現它對Java的支持也做得特別好。最讓我喜歡的一點是,它可以一鍵安裝和管理多個Java版本。我可以同時安裝Java 8、11、17、21等多個版本,它們之間完全隔離,互不干擾。
而且,我還可以為不同的項目指定使用不同的Java版本。比如,可以設置項目A的運行環境就是Java 8,項目B就是Java 23。這樣一來,在切換項目時,根本不用關心JDK版本的問題,ServBay都幫你自動處理好了。
對於我們Java開發者來説,這意味着可以把更多精力放在代碼和技術本身,而不是被環境配置這些瑣事消耗。
總結
Java依然是一門生命力旺盛的語言。學習和使用這些技巧,可以讓我們的代碼質量更高,開發體驗也更好。而藉助像ServBay這樣的工具,又能幫我們輕鬆搞定複雜的環境管理問題,讓我們能更專注於寫出優秀的代碼。
你還有什麼私藏的Java技巧嗎?歡迎在評論區分享交流。