如果像 AI 一样写 Lambda(第 3 篇):转换与过滤(Stream 应用篇)
一句话总结:
map负责把元素"换件衣服",filter负责"筛掉不合格的",removeIf负责"当场赶走"。AI 会尽可能用::把三者写成一行。
相关文档:《如果像AI一样写Lambda-第1篇-函数式接口-通俗版.md》——map的地基是Function,filter的地基是Predicate。
0. 比喻:流水线工厂
| 写法 | 比喻 |
|---|---|
| 普通人的写法 | 老师傅手工:拿一件、加工一件、放一件 |
| 函数式写法 | 流水线:每道工序贴一张"操作规则" |
| AI lambda 简写 | 工序牌只写工具名:“打磨机”、“质检章” |
1. map:逐个转换
场景:把一堆带空格的名字统一 trim 干净。
① 普通人的写法:for 循环逐个加工
Stringraw="AP S&P Partners, AP Tablet Partners, 2 Telco";String[]parts=raw.split(",");List<String>items=newArrayList<>();for(Stringpart:parts){items.add(part.trim());}② 函数式写法:map + 完整 lambda
List<String>items=Arrays.stream(raw.split(",")).map(part->part.trim()).collect(Collectors.toList());③ AI lambda 简写:方法引用
List<String>items=Arrays.stream(raw.split(",")).map(String::trim).collect(Collectors.toList());String::trim很特殊:左边是类名而非实例。它等价于part -> part.trim(),流中的元素既是调用者又是参数。AI 看到"拿到元素 → 调它自己的无参方法"就会写类名::方法名。
2. filter:保留合格的
场景:滤掉列表里的 null。
① 普通人的写法:for + if 手工挑
List<String>result=newArrayList<>();for(Stringid:ids){if(id!=null){result.add(id);}}② 函数式写法:filter + 完整 lambda
List<String>result=ids.stream().filter(id->id!=null).collect(Collectors.toList());③ AI lambda 简写:方法引用
List<String>result=ids.stream().filter(Objects::nonNull).collect(Collectors.toList());Objects::nonNull是 JDK 自带的官方方法引用,专门用来滤 null。这一步很关键:如果放任 null 流到下游(比如拼字符串),null 会被拼成 “null” 四个字符,埋下脏数据隐患。
3. removeIf:原地删除
场景:从名单里删掉所有排除项。
① 普通人的写法:迭代器边遍历边删
List<String>items=newArrayList<>(Arrays.asList("AP S&P Partners","Lenovo Global","2 Telco"));Iterator<String>it=items.iterator();while(it.hasNext()){Stringitem=it.next();if(EXCLUDE_NAMES.contains(item)){it.remove();}}② 函数式写法:removeIf + 完整 lambda
items.removeIf(item->EXCLUDE_NAMES.contains(item));③ AI lambda 简写:方法引用
items.removeIf(EXCLUDE_NAMES::contains);removeIf的返回值是 boolean(是否真的删过元素),所以 AI 敢直接把它当条件用:
returnitems.removeIf(EXCLUDE_NAMES::contains)?String.join(",",items):original;删过 → 返回重新拼接的结果;没删过 → 返回原值。一次遍历同时完成"判断 + 删除 + 汇报",这就是 AI 风格的典型表达。
4. 为什么增强 for 里不能直接删
// ❌ 会抛 ConcurrentModificationExceptionfor(Stringitem:items){if(EXCLUDE_NAMES.contains(item)){items.remove(item);}}增强 for 本质是迭代器,遍历中修改集合会触发"并发修改"异常。传统写法必须用Iterator.remove(),而removeIf在内部替你安全地干了这件事——这就是它存在的意义。
5. map / filter / removeIf 对照表
| API | 作用 | 返回值 | 元素去哪了 |
|---|---|---|---|
map | 逐个转换 | 新 Stream | 换装后继续往下走 |
filter | 保留满足条件的 | 新 Stream | 不合格的被丢弃 |
removeIf | 原地删除满足条件的 | boolean | 直接从原 List 里消失 |
map/filter是"无中生有"的流水线,不碰原集合;removeIf是"当场执法",直接改原 List。
6. 陷阱:removeIf 对不可变集合失效
// ❌ Arrays.asList 返回的是"只可改值、不可增删"的定长 ListList<String>fixed=Arrays.asList("A","B","C");fixed.removeIf("B"::equals);// 抛 UnsupportedOperationException解法:先包一层new ArrayList<>(...)变成可变集合,再removeIf:
List<String>mutable=newArrayList<>(Arrays.asList("A","B","C"));mutable.removeIf("B"::equals);// ✅ 正常一页速记
map(类名::无参方法)= 对每个元素调它的方法,如String::trimfilter(Objects::nonNull)= 滤掉 null 的官方姿势removeIf(Set::contains)= 安全版"边遍历边删除",自带 boolean 返回值- 增强 for 里直接 remove 会炸,传统做法用
Iterator.remove() map/filter不碰原集合,removeIf直接改原 ListremoveIf只能用于可变集合,Arrays.asList需要先new ArrayList<>()- lambda 体只有一句"调用现成方法" → 一律考虑改成
::