問:“Java 8 有啥新東西?”
你憋了半天,只說出一句:“嗯……有 Lambda 表達式。”
別慌!Java 8 可不只是“語法糖”那么簡單。它是一次真正讓 Java 從“老派”走向“現代” 的大升級!
一、Lambda 表達式:告別“模板代碼”,代碼瘦身 50%
? 是什么?
Lambda 表達式是一種簡潔地表示“一段可執行代碼” 的方式。
它讓你可以把“函數”當作參數傳遞,不再需要寫一堆匿名內部類。
🧱 以前怎么寫(痛苦版):
// 給一個用戶列表按年齡排序
List<User> users = getUsers();Collections.sort(users, new Comparator<User>() {@Overridepublic int compare(User u1, User u2) {return u1.getAge() - u2.getAge();}
});
光排序就寫了 6 行!而且 new Comparator<User>()
這種寫法,是不是特別“啰嗦”?
🚀 現在怎么寫(爽快版):
// 一行搞定!
users.sort((u1, u2) -> u1.getAge() - u2.getAge());
->
左邊是參數,右邊是邏輯。干凈、清晰、易讀!
💡 高分回答:
“Lambda 讓我最爽的是減少了‘模板代碼’。比如排序、線程創建、事件監聽,以前都要寫匿名類,現在一行搞定。代碼更簡潔,也更容易理解。”
二、Stream API:集合操作的“SQL 語言”
? 是什么?
Stream 不是集合,而是一種對集合進行“流水線式”操作的工具。
你可以像寫 SQL 一樣,用 filter
、map
、reduce
等方法處理數據。
🧱 以前怎么寫(嵌套地獄):
// 找出所有年齡 > 18 的用戶,提取名字,轉成大寫,去重,放到新列表
List<String> result = new ArrayList<>();
Set<String> seen = new HashSet<>();for (User user : users) {if (user.getAge() > 18) {String name = user.getName().toUpperCase();if (!seen.contains(name)) {seen.add(name);result.add(name);}}
}
邏輯簡單,但代碼又臭又長,還容易出錯。
🚀 現在怎么寫(行云流水):
List<String> result = users.stream().filter(u -> u.getAge() > 18) // 過濾.map(u -> u.getName().toUpperCase()) // 轉換.distinct() // 去重.collect(Collectors.toList()); // 收集結果
像流水線一樣,數據從左到右“流”過每個操作,邏輯清晰得像讀句子!
💡 實戰場景:
“我們做報表時,要從上千條訂單中篩選出‘已支付’的,按用戶分組,計算總金額。用 Stream 幾行代碼就搞定,以前得寫幾十行循環和判斷。”
? 面試高分回答:
“Stream 讓集合操作變得聲明式。我不再關心‘怎么遍歷’,而是專注‘要做什么’。它提升了代碼的可讀性和可維護性,特別是在數據處理、報表生成這類場景中優勢明顯。”
三、Optional:徹底告別“空指針異常”
? 是什么?
Optional<T>
是一個容器,用來包裝可能為 null 的對象,強制你去處理“空值”情況,避免 NullPointerException
。
🧱 以前怎么寫(提心吊膽):
User user = getUserById(1001);
if (user != null) {Address addr = user.getAddress();if (addr != null) {String city = addr.getCity();if (city != null) {System.out.println("城市:" + city);}}
}
層層嵌套的 if (xxx != null)
,像“回調地獄”一樣難看。
🚀 現在怎么寫(優雅從容):
Optional<User> userOpt = Optional.ofNullable(getUserById(1001));userOpt.flatMap(u -> Optional.ofNullable(u.getAddress())).flatMap(a -> Optional.ofNullable(a.getCity())).ifPresent(city -> System.out.println("城市:" + city));
或者更簡單:
String city = userOpt.map(User::getAddress).map(Address::getCity).orElse("未知城市");
💡 實戰場景:
“我們接口返回的數據,有些字段可能為空。以前經常線上報空指針。現在用
Optional
包裝返回值,明確告訴調用方‘可能為空’,并提供默認值,穩定性提升很多。”
? 高分回答:
“Optional 不是消滅 null,而是讓我們更‘顯式’地處理 null。它把‘空值’變成一種類型安全的設計,減少了運行時異常,也讓代碼的意圖更清晰。”
四、方法引用:Lambda 的“快捷方式”
? 是什么?
當 Lambda 的邏輯正好是某個已有方法的實現時,可以用 ::
直接引用它,更簡潔。
🚀 常見寫法:
// Lambda
list.forEach(s -> System.out.println(s));
// 方法引用(更簡潔)
list.forEach(System.out::println);// Lambda
users.sort((u1, u2) -> u1.getName().compareTo(u2.getName()));
// 方法引用
users.sort(Comparator.comparing(User::getName));
💡 記住這四種:
對象::實例方法
:System.out::println
類::靜態方法
:Integer::parseInt
類::實例方法
:String::compareTo
(第一個參數是調用者)構造器::new
:User::new
五、新的日期時間 API(JSR-310):終于好用了!
? 以前有多坑?
Date
和 Calendar
是線程不安全的,API 設計反人類,比如月份從 0 開始!
🚀 Java 8 怎么改的?
引入了 java.time
包,核心類:
LocalDateTime
:日期時間(無時區)ZonedDateTime
:帶時區的日期時間Duration
?/?Period
:計算時間差
🎯 實戰代碼:
// 獲取當前時間
LocalDateTime now = LocalDateTime.now();// 3天后
LocalDateTime threeDaysLater = now.plusDays(3);// 解析字符串
LocalDateTime dt = LocalDateTime.parse("2025-08-07T16:00:00");// 格式化輸出
String formatted = dt.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm"));
💡 加分點:
“我們項目之前用
SimpleDateFormat
,結果多線程下解析時間出錯。換成DateTimeFormatter
(不可變、線程安全)后,問題徹底解決。”
? 面試終極回答模板(背下來!)
“Java 8 是一次里程碑式的升級。我最常用的是 Stream API 和 Optional。
比如在做數據清洗時,用 Stream 鏈式操作過濾、轉換、聚合,代碼清晰易維護;
用 Optional 處理可能為空的查詢結果,避免空指針,提升系統穩定性。
Lambda 和方法引用讓代碼更簡潔,新的時間 API 解決了老日期類的線程安全問題。
這些特性讓我寫的代碼更少、更安全、更易讀。”
🔚 總結:Java 8 到底強在哪?
特性 | 解決了什么痛點 | 面試怎么說 |
---|---|---|
Lambda | 匿名類太啰嗦 | “讓代碼更簡潔,函數可傳遞” |
Stream | 集合操作復雜 | “像 SQL 一樣處理數據,聲明式編程” |
Optional | 空指針異常 | “顯式處理 null,提升健壯性” |
方法引用 | Lambda 還是有點長 | “復用已有方法,更簡潔” |
新時間 API | 日期類難用且不安全 | “線程安全,API 設計合理” |
記住:Java 8 不是“新語法”,而是“新思維”——從“命令式”走向“函數式”,從“防錯”走向“設計安全”。