最开始还准备一周一总结,结果因为懒鸽了这么多周,这周就从第二周开始算。
先说下都学了什么,从泛型、Map/Set 集合用法,到Lambda 表达式、方法引用,我觉得这部分好抽象,学的时候也很吃力,所以遇到了相当多的问题,也可能是我没有去用的原因。本篇总结将对我遇到的问题,我不理解的地方做个总结。
一、泛型:保障数据类型不会出错,简化代码
先学的是泛型,从 “为什么要用”“什么时候用”两个问题,我理解了泛型。
1. 为什么要用:
(1)有一些限定集合 / 工具类的存储类型,你去存数据的时候,可能会手误把另一种数据存进去了,这时候明显是有问题的。但它在编译时不显示错误,在运行时给你报一个ClassCastException异常
(2)这种存储类型,不管你存进去是什么类型,取出来都是Object,所以取出来还要强转
// 不使用泛型:需要强制转换,麻烦且不安全
List list = new ArrayList();
list.add("Java");
//这个编译不报错,但运行时报错
//list.add(100);
String s1 = (String) list.get(0); // 必须强转
// 使用泛型:不用强转,安全、简洁、清晰
List<String> list2 = new ArrayList<>(); list2.add("Java"); S
tring s2 = list2.get(0); // 直接使用,无需强转
为了解决这些问题,泛型诞生了。把类型名填入<>,对类型强制规范,让错误在编译时给你报出来,避免运行时异常。
让你存进去什么类型,取出来还是什么类型,免去强制类型转换。
2. 关键疑问解答
不强转会怎样:不用泛型时,集合存储的都是Object类型,无法调用子类特有方法,必须强转才能使用;
足够细心能不能不用泛型?这是我的一个疑问。答案是可以,但人无法保证永远不出错,泛型能把错误提前到编译期,项目更稳健;
3. 使用场景判断
必须用:通用容器、工具类、需要保证类型安全的场景,如List、Set、Map;
不用:仅处理单一固定类型、无需复用的简单业务逻辑。
二、Map 集合:遍历、Entry 与 TreeMap 排序
Map 是本周学习的一个难点集合,理清了HashMap遍历规则、Entry作用,以及TreeMap使用注意事项。
1. 先说Map是什么,为什么用,什么时候用
- Map 是一种用来存储「键值对(Key-Value)」的集合,就像字典一样,根据Key能找到Value
- 根据 key 快速查找 value,速度极快;需要一个集合能存储一对一对的数据
- 存在一一对应关系数据,用map存储;需要快速查找;需要做映射
2. HashMap 三大遍历方法
keySet():获取所有键的Set集合(键唯一,匹配Set不可重复特性);values():获取所有值的Collection集合(值可重复,用Collection更适配);entrySet():最推荐遍历方式,获取Entry键值对集合,一次性拿到 key 和 value,高效无冗余。
3. Map.Entry 的作用
Entry是 Map 中键值对的封装对象,entrySet()将所有 key+value 打包成集合,遍历时直接获取对应关系,避免单独查值的多余操作。
4. TreeMap 排序问题与解决
-
当你用TreeMap存引用数据类型数据,特别是自定义的类对象,它就会报错。报错原因:
TreeMap默认自动排序,key 必须具备比较能力,否则会抛出ClassCastException; -
两种解决方案:
- 自定义类实现
Comparable接口,重写compareTo方法; - 创建
TreeMap时传入Comparator比较器(可用 Lambda / 方法引用简化)。
- 自定义类实现
4. 排序小技巧
这是我遇到的一个小问题,比较浮点型数值用Double.compare(),避免减法运算导致的精度丢失。
三、Set 集合:remove 方法核心用法
Set.remove(Object o)是 Set 的核心删除方法:
- 作用:删除集合中指定的元素对象,删除成功返回
true,元素不存在返回false; - 重点:Set无索引,不能通过下标删除,底层依靠
hashCode()+equals()判断元素是否一致。
四、Lambda 与方法引用:语法糖与延迟执行
这是本周最难但最实用的知识点,理解了匿名内部类→Lambda→方法引用的简化逻辑,以及延迟执行的性能优化意义。
1. 匿名内部类的作用
接口无法直接实例化,但又不想再创建一个类去实现接口。就有了匿名内部类,匿名内部类用于临时一次性实现接口,无需单独创建实现类,是 Lambda 的原始写法。
2. 方法引用的本质
Lambda 的极简语法糖,格式:类名::方法名/对象::方法名,直接复用已有方法,代码更简洁。
3. 延迟执行(核心优化)
- 有时候,一些操作最终不会被执行,但它的前置操作会执行,从而造成性能浪费。延迟执行就是应对这种情况。
- 举个例子
//MsgBuilder(函数式接口,核心)
// 函数式接口:用于构建字符串的抽象行为
public interface MsgBuilder {
String buildMsg(String... infos);
}
//PrintUtil.java(核心延迟执行逻辑)
public class PrintUtil {
// 字符串拼接的核心方法
private static String build(String... infos) {
StringBuilder builder = new StringBuilder();
for (String info : infos) {
builder.append(info);
}
return builder.toString();
}
// 核心:延迟执行 - 只有valid为true时,才会执行字符串构建
public static void print(boolean valid, String... infos) {
if (valid) { // 方法引用(Lambda简化):将构建行为传递,而非直接传递构建结果
MsgBuilder builder = PrintUtil::build;
System.out.println(builder.buildMsg(infos));
}
}
}
public class PrintTest {
public static void main(String[] args) {
String name = "Merry";
String desc = "is friendly";
// 场景1:valid=false → 不会执行字符串拼接(无性能损耗)
PrintUtil.print(false, name, desc);
// 场景2:valid=true → 才会执行字符串拼接并打印(延迟执行)
PrintUtil.print(true, name, desc);
}
}
- 传统写法:字符串提前拼接,即使不打印也会执行,造成性能浪费;
- Lambda 延迟:将拼接逻辑封装在函数式接口中,仅当需要打印时才执行,从根源避免无效计算。
4. 小小吐槽
可能是我悟性不够吧,但我看的课里在教Lambda延迟执行时,非要扯上方法引用,搞得我很不理解,延迟执行关方法引用啥事。
五、一周学习心得
-
核心收获:
- 所有语法糖(Lambda、方法引用)底层逻辑不变,只是简化写法;
- 泛型、延迟执行都是为了提升代码安全性与性能;
- 集合用法有明确规则,选对遍历方式、排序方式能少踩坑;
-
后续方向:深入 Stream 流的中间 / 终结操作、函数式接口实战、集合底层原理。