Stream.map(Function<T,R>) 將流中每個元素映射為新元素,形成新流,元素數量不變但類型可變。這是函數式編程中「函子」概念在 Java 的體現。
List friends = Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
// 命令式:可變集合、外部迭代
List uppercase = new ArrayList<>();
for (String name : friends) uppercase.add(name.toUpperCase());
// 函數式:不可變、內建迭代、管道式
friends.stream()
.map(String::toUpperCase) // 方法引用
.forEach(System.out::println); // 終端操作觸發執行
// 輸出:BRIAN NATE NEAL RAJU SARA SCOTT
friends.stream()
.map(String::length) // String -> Integer
.forEach(len -> System.out.print(len + " "));
// 輸出:5 4 4 4 4 5
record User(String name, int age, String email) {}
record UserDTO(String name, boolean adult, String domain) {}
List users = List.of(
new User("Alice", 25, "alice@gmail.com"),
new User("Bob", 17, "bob@yahoo.com")
);
List dtos = users.stream()
.map(u -> new UserDTO(
u.name(),
u.age() >= 18,
u.email().substring(u.email().indexOf('@') + 1)
))
.toList();
@FunctionalInterface
interface ThrowingFunction {
R apply(T t) throws Exception;
}
static Function wrap(ThrowingFunction f) {
return t -> {
try { return f.apply(t); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
// 使用
List urls = List.of("https://a.com", "https://b.com");
List docs = urls.stream()
.map(wrap(url -> Jsoup.connect(url).get())) // Jsoup 拋出 IOException
.toList();
// 只轉換滿足條件的元素,其餘保持原樣
List mixed = List.of("apple", "BANANA", "Cherry");
List result = mixed.stream()
.map(s -> s.equals(s.toUpperCase()) ? s.toLowerCase() : s.toUpperCase())
.toList(); // 全部大小寫反轉
// 只有大寫才轉小寫,其他不變
List result2 = mixed.stream()
.map(s -> s.equals(s.toUpperCase()) ? s.toLowerCase() : s)
.toList();
「傳遞參數給方法」的 Lambda 應改用方法引用(俗稱「外包模式」):
| 場景 | Lambda | 方法引用 | 建議 |
|---|---|---|---|
| 單純轉發 | x -> x.toUpperCase() | String::toUpperCase | 方法引用 |
| 需額外參數/邏輯 | x -> transform(x, config) | 不可用 | Lambda |
| 建構子 | x -> new DTO(x) | DTO::new | 方法引用 |
| 靜態方法 | x -> Util.parse(x) | Util::parse | 方法引用 |
.parallelStream() 自動分割任務至 ForkJoinPool,無共享狀態時線性加速IntStream/LongStream/DoubleStream 避免裝箱拆箱,數值計算效能大增// 數值計算優先用基本型別流
double avg = prices.stream()
.mapToDouble(BigDecimal::doubleValue) // 轉為 DoubleStream
.filter(p -> p > 20)
.map(p -> p * 0.9)
.average()
.orElse(0.0);
Optional 或 filter(Objects::nonNull)collect/toList 保持管道可組合mapToInt/Double/LongSpliterator 或資料庫游標,避免一次性載入記憶體map 是 Stream 轉換的核心,掌握其與 filter、flatMap、reduce 的組合模式,能解決 90% 的集合處理需求。記住三原則:不可變、無副作用、類型清晰,讓編譯器與 JVM 幫你優化。