问:“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 不是“新语法”,而是“新思维”——从“命令式”走向“函数式”,从“防错”走向“设计安全”。