動態

詳情 返回 返回

寫了這麼多年Java,這幾個神仙技巧你用過嗎? - 動態 詳情

如果你也是從 public static void main(String[] args)System.out.println() 開始Java生涯的,那也是Java老油條了。在日常的業務開發中,我們每天都在寫着增刪改查的邏輯,有時候會覺得Java有點笨重,語法有點囉嗦。

但其實,Java在不斷進化。從我們熟悉的Java 8到現在的Java 25,它多了很多實用的新特性和一些不為人知的老技巧。用好它們,不僅能讓代碼更簡潔,還能在同事面前小小地秀一下。

image.png

下面就聊幾個我自己在工作中覺得特別好用的技巧,看看你用過幾個。

用枚舉(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等多個版本,它們之間完全隔離,互不干擾。

image.png

而且,我還可以為不同的項目指定使用不同的Java版本。比如,可以設置項目A的運行環境就是Java 8,項目B就是Java 23。這樣一來,在切換項目時,根本不用關心JDK版本的問題,ServBay都幫你自動處理好了。

對於我們Java開發者來説,這意味着可以把更多精力放在代碼和技術本身,而不是被環境配置這些瑣事消耗。

總結

Java依然是一門生命力旺盛的語言。學習和使用這些技巧,可以讓我們的代碼質量更高,開發體驗也更好。而藉助像ServBay這樣的工具,又能幫我們輕鬆搞定複雜的環境管理問題,讓我們能更專注於寫出優秀的代碼。

你還有什麼私藏的Java技巧嗎?歡迎在評論區分享交流。

user avatar dirackeeko 頭像 ccVue 頭像 licin 頭像 jkdataapi 頭像 best-doraemon 頭像 lyhabc 頭像 tully_l 頭像 digitalocean 頭像 mangrandechangjinglu 頭像 meiyoufujideyidongdianyuan 頭像 smartbidashuju 頭像 datadowell 頭像
點贊 25 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.