Java知识
值传递和引用传递
- 实际上只有值传递,传递值的副本
- 引用传递是传递地址作为值的副本,所以修改成员会影响原来的对象
- 基本类型值传递;引用类型(对象,数组等)引用传递
int 和 Integer
int 是基本数据类型,直接计算
Integer 是 Integer 对象,用各种方法Integer.parseInt(String s)将字符串转为 int(基本类型)Integer.max(int a, int b)返回较大值Integer.toString(a)转换成字符串
1 | |
Java 类中的静态变量和静态方法
在 Java 中,静态变量和静态方法是与类本身关联的
而不是与类的实例关联。它们在内存中只存在一份,可以被类的所有实例共享
Java 里面的引用类型
Java 的所有非基本类型都是 引用类型(对象通过引用访问)
Collection 是 List,Set,Queue 等接口的根接口;Map 是 HashMap 和 TreeMap 等类实现的根接口
| Java 类型 | C++ 对应类型 | JAVA 功能描述 |
|---|---|---|
String |
std::string |
不可变对象(immutable),通过引用操作 |
int[] |
原生数组或std::vector |
数组是对象,带长度属性(arr.length),自动内存管理 |
List<T> (如 ArrayList) |
std::vector<T> |
List是接口,ArrayList是动态数组实现 |
Map<K,V> (如 HashMap) |
std::unordered_map<K,V> |
HashMap基于哈希表,无序 |
Set<T> (如 HashSet) |
std::unordered_set<T> |
HashSet基于哈希表,无序且唯一 |
自定义类(class Person) |
class Person |
对象通过引用访问(类似智能指针) |
Java 引用类型的使用
字符串:String name = "Alice";
动态数组:List<Integer> numbers = new ArrayList<>();
哈希表:Map<String, Integer> map = new HashMap<>();
自定义类:Person person = new Person("Alice", 18);
接口复用代码
Java 只有单继承(extends ),但可以实现(implements) 多个接口
从 Java 8 开始接口可以有:
- 默认方法(default):提供默认实现
- 静态方法(static):工具方法
- 私有方法(private):默认辅助方法
用接口复用代码的例子
1 | |
lambda 表达式
Java 8 引入了 lambda 表达式
简化了匿名内部类的写法
(a, b) -> a + b
(a, b) -> {a + b; return a + b;}// 多条语句要用{}
stream 的 API
适合集合对象的操作,如过滤,映射,排序,聚合等
问题场景:从一个列表中筛选出所有长度大于 3 的字符串,并收集到一个新的列表中。
没有 Stream 啲做法:
1 | |
使用 Stream API 的做法:
1 | |
originalList.stream():创建一个流,该流包含原始列表中的所有元素。.filter(s -> s.length() > 3):对流进行过滤,只保留长度大于 3 的字符串。.collect(Collectors.toList()):将过滤后的结果收集到一个新的列表中。
其他案例:字符串统一排序
map(s -> s.toUpperCase()):将每个字符串转换为大写。.sorted():对字符串进行排序。.collect(Collectors.joining(", ")):将排序后的字符串连接成一个字符串,并使用逗号(,)作为分隔符。
计算数字列表的和
numbers.stream():创建一个流,该流包含原始列表中的所有数字。.mapToInt(Integer::intValue):将数字映射为 int 类型。.sum():计算数字的和。
cpu 密集的运算用 Stream 并行
I/O 密集的运算用 Stream 串行
终端操作
终端操作是流管道(stream pipeline)中的最后一个操作,是触发流管道执行的操作。
一旦调用,流就被 消费(consumed),不能再被使用。
与中间操作(如 filter, map)不同,终端操作 不返回 Stream,而是返回
所有 Java stream API 的终端操作
| 类别 | 方法 | 功能说明 | 返回类型 | 是否短路 |
|---|---|---|---|---|
| 遍历 / 副作用 | forEach(action) |
对每个元素执行操作(并行流中无序) | void |
否 |
forEachOrdered(action) |
按照流的原始顺序执行操作(即使并行流也保序) | void |
否 | |
| 收集结果 | collect(Collectors.toList())(典型用法) |
将流元素收集到 List(也可 toSet(), joining() 等) |
R(如 List<T>) |
否 |
toArray() |
转为 Object[] 数组 |
Object[] |
否 | |
toArray(String[]::new)(示例) |
转为指定类型数组(如 String[]) |
T[] |
否 | |
| 归约 | reduce(初始值, 累加器) |
从初始值开始,依次合并元素(如字符串拼接、求和) | T |
否 |
reduce(累加器) |
无初始值归约,流为空时返回 Optional.empty() |
Optional<T> |
否 | |
| 查找与匹配 | findFirst() |
返回第一个元素(适合有序流) | Optional<T> |
✅ 是 |
findAny() |
返回任意一个元素(适合并行流,更快) | Optional<T> |
✅ 是 | |
anyMatch(pred) |
是否存在至少一个元素满足条件 | boolean |
✅ 是 | |
allMatch(pred) |
是否所有元素都满足条件 | boolean |
✅ 是(遇到 false 即停) | |
noneMatch(pred) |
是否没有元素满足条件 | boolean |
✅ 是(遇到 true 即停) | |
min(comparator) |
返回最小元素(按比较器) | Optional<T> |
否 | |
max(comparator) |
返回最大元素 | Optional<T> |
否 | |
| 计数 | count() |
返回流中元素总数 | long |
否 |
中间操作
| 类别 | 方法 | 功能说明 | 返回类型 |
|---|---|---|---|
| 过滤 | filter(Predicate<? super T> predicate) |
保留满足条件的元素 | Stream<T> |
| 映射 / 转换 | map(Function<? super T, ? extends R> mapper) |
将每个元素转换为另一种类型 | Stream<R> |
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) |
将每个元素映射为一个流,然后扁平化合并为一个流 | Stream<R> |
|
mapToInt(ToIntFunction<? super T> mapper) |
转为 IntStream(用于基本类型优化) |
IntStream |
|
mapToLong(...) / mapToDouble(...) |
类似,分别转为 LongStream / DoubleStream |
LongStream / DoubleStream |
|
| 排序 | sorted() |
按自然顺序排序(要求元素实现 Comparable) |
Stream<T> |
sorted(Comparator<? super T> comparator) |
按指定比较器排序 | Stream<T> |
|
| 去重 | distinct() |
去除重复元素(基于 equals()) |
Stream<T> |
| 截取 | limit(long maxSize) |
保留前 maxSize 个元素 |
Stream<T> |
skip(long n) |
跳过前 n 个元素 | Stream<T> |
|
| 查看 / 调试 | peek(Consumer<? super T> action) |
对每个元素执行操作(常用于调试),不影响流本身 | Stream<T> |
| 并行 / 串行控制 | parallel() |
将流转换为并行流 | Stream<T> |
sequential() |
将流转换为顺序流 | Stream<T> |
|
unordered() |
忽略流的顺序性(可能提升并行性能) | Stream<T> |
责任链模式
一个请求需要多个处理逻辑时的灵活做法
比如各种校验逻辑
先定义一个抽象处理者类
1 | |
然后每个校验逻辑都继承这个类,比如登录逻辑
1 | |
然后再写其他节点,最后根据需要动态添加节点
1 | |
这样一来,发起方只需要调用第一个节点,不用关心后面有多少校验步骤
如果某个接口不需要某个校验就直接去掉这个节点就行,非常灵活