四. Stream
流
1. 描述
流模式: 对流元素按队列(顺序)进行聚合操作
串行: 以单一数据块执行
并行: 切分为多数据块执行
通常是为了简化集合和数组的遍历操作
2. 格式
聚合函数连续调用
3. 特征
元素队列元素 是特定类型的对象, 形成一个队列。 Java
中的Stream
并不会存储元素, 也不会改变原对象, 而是按需计算。
数据源 流的来源。 可以是集合,数组,I/O channel
, 产生器generator
等。
聚合操作 处理结果是新的Stream
流, 类似SQL
语句一样的操作, 比如filter
, map
, reduce
, find
, match
, sorted
等。
终止操作 结果不再是流,而是流元素的实例或者操作结果, 比如:forEache
, count
, collect
和以前的Collection
操作不同, Stream
操作还有两个基础的特征:
Pipelining
: 中间操作都会返回新的流对象。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style
)。
内部迭代: 以前对集合遍历都是通过Iterator
或者For-Each
的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。Stream
提供了内部迭代的方式, 通过访问者模式(Visitor
)实现。
注意:
Stream
流是延迟执行的, 只有在执行结束操作(有结果时)时,才会执行之前的Stream
操作
以下Stream
流中调用了map
聚合函数, 并在该聚合函数中添加了打印信息
但控制台并未输出相关内容
调用终止函数后, 打印了内容数据
private static void streamStart() {
List<Box> boxes = GenerateUtil.generateBoxes();
System.out.println("测试流过程开始");
Stream<String> stringStream = boxes.stream()
.map(box -> {
System.out.println("box: " + box);
return box.getColor();
});
System.out.println("流过程初始化完成");
// 遇到count时执行stream流
long count = stringStream.count();
System.out.println("测试流过程结束");
}
- 调用聚合函数后返回的是新的
Stream
流
private static void otherStream() {
List<Box> boxes = GenerateUtil.generateBoxes();
System.out.println("测试流过程开始");
Stream<Box> stream1 = boxes.stream();
System.out.println(stream1);
Stream<Box> stream2 = stream1.filter(box -> box.getSize() >= 3);
System.out.println(stream2);
Stream<String> stream3 = stream2.map(Box::getColor);
System.out.println(stream3);
System.out.println("测试流过程结束");
}
4. 案例
- 获取流的方法
Stream.of()
和Collection.stream()
private static void streamOf() {
Stream<String> stringStream = Stream.of("a", "b", "c");
String[] a = {"a", "b", "c"};
Stream.of(a).forEach(System.out::println);
List<Box> boxes = GenerateUtil.generateBoxes();
Stream<Box> stream1 = boxes.stream();
}
forEach
方法
参考上述内容
终止函数
对流元素进行遍历操作, 返回值为voidcount
方法
终止函数
对当前Stream
流中的流元素进行计数并返回为long
private static void count() {
List<Box> boxes = GenerateUtil.generateBoxes();
long count = boxes.stream().count();
System.out.println("初始size:" + count);
long count1 = boxes.stream().filter(box -> box.getSize() >= 3).count();
System.out.println("过滤后size:" + count1);
}
4. reduce
方法
终止函数
将当前Stream
流中的流元素进行归约操作, 上一次操作的结果作为这一次操作的一个 参数
private static void reduce() {
Integer[] numbers = {2, 1, 1, 4, 1, 6, 2};
List<Integer> num = new ArrayList<>(Arrays.asList(numbers));
Integer reduce = num.stream()
.reduce(0, (result, item) -> result += item);
System.out.println(reduce);
}
第一: 操作项不限于数值
第二: 处理操作不限于sum,max
等数值计算, 也可以用作字符串拼接等
第三: result
参数类型与处理操作返回值的类型相同, item
参数类型与当前Stream
流中的 泛型类型相同
5. find
方法
终止函数
查找元素
findFirst
->查找第一个元素
findAny
->查找任意一个元素(串行Stream
流也是查找第一个元素)
private static void find() {
OptionalInt any = IntStream.range(0, 100000).parallel().findAny();
any.ifPresent(System.out::println);
}
6. match
方法
终止函数
流元素匹配内容的结果
allMatch
-> 全元素匹配
anyMatch
-> 有匹配元素
noneMatch
-> 没有匹配元素
private static void match() {
String[] strings = {"auyj", "byjk", "cyp89i", "dyuj"};
boolean a = Stream.of(strings).anyMatch(item -> item.startsWith("a"));
System.out.println(a);
}
collect
方法
终止函数
将Stream
流转换为其他形式
private static void count() {
List<Box> boxes = GenerateUtil.generateBoxes();
Set<Box> boxes2 = boxes.stream().collect(Collector::toSet);
}
filter
方法
聚合函数
对当前Stream
流中的流元素进行筛选操作, 返回新的Stream
流
private static void filter() {
Integer[] numbers = {1, 2, 3, 4, 5, 6, 7};
Stream<Integer> stream1 = Stream.of(numbers);
System.out.println("过滤前内容:");
stream1.forEach(System.out::println);
System.out.println("过滤后内容:");
Stream<Integer> stream2 = Stream.of(numbers);
stream2.filter(box -> box > 3).forEach(System.out::println);
}
9. map
方法
聚合函数
对当前Stream
中的流元素进行处理, 并返回新的映射元素的Stream
流
private static void map() {
List<Box> boxes = GenerateUtil.generateBoxes();
boxes.stream()
.map(Box::getColor) //处理操作
.forEach(System.out::println); //遍历输出
}
10. distinct
方法
聚合函数
对当前Stream
流中的流元素进行去重,使用equals
方法和hashCode
方法判断(基本类型 使用”==
”)是否相等
private static void distinct() {
Integer[] numbers = {1, 2, 1, 4, 1, 6, 2};
Stream.of(numbers).distinct().forEach(System.out::println);
}
11. sorted
方法
聚合函数
对Stream
流中的流元素进行规则排序
private static void sort() {
Integer[] numbers = {2, 1, 1, 4, 1, 6, 2};
List<Integer> num = new ArrayList<>(Arrays.asList(numbers));
List<Integer> collect = num.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(collect);
}
12. skip
方法
聚合函数
从当前Stream
流中跳过前n
条数据(舍弃前n
条数据)
private static void skip() {
Integer[] numbers = {2, 1, 1, 4, 1, 6, 2};
List<Integer> num = new ArrayList<>(Arrays.asList(numbers));
List<Integer> collect = num.stream()
.skip(3)
.collect(Collectors.toList());
System.out.println(collect);
}
13. limit
方法
聚合函数
从当前Stream
流中截取前n
条数据()舍弃之后的数据)
private static void limit() {
Integer[] numbers = {2, 1, 1, 4, 1, 6, 2};
List<Integer> num = new ArrayList<>(Arrays.asList(numbers));
List<Integer> collect = num.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println(collect);
}
截取了前三条数据, 数值小于 0 ,会抛出IllegalArgumentException
14. concat
方法
聚合函数
静态方法
对两个Stream
流中的流元素进行合并, 获得合并后的元素Stream
流
private static void concat() {
Integer[] numbers = {2, 1, 1, 4};
List<Integer> num = new ArrayList<>(Arrays.asList(numbers));
String[] strings = {"a", "b", "c", "d"};
List<String> strs = new ArrayList<>(Arrays.asList(strings));
List<? extends Serializable> collect = Stream.concat(num.stream(), strs.stream())
.collect(Collectors.toList());
System.out.println(collect);
}
合并操作会操作泛型, 如果流元素的泛型类型相同则结果就是该泛型类型,如果不相同, 则会返回公共父类类型作为泛型
五. JAVA
日期
1. 描述
LocalDate
: 当地日期
LocalTime
: 当地时间
LocalDateTime
: 当地日期时间, 内部维护LocalDate
和LocalTime
ZonedDateTime
: 带有时区的日期时间
Instante
: 时间戳
2. 新特点
- 线程安全、不可修改
- 月份星期改为枚举
- 将日期和时间分开
- 简化了时区问题
3. 案例
注意: 为便于描述, 以下描述中的 ‘日期’ 均指代日期(LocalDate)与时间(LocalTime)
- 创建
now
: 创建 ‘日期’ 实例
of
: 创建目标 ‘日期’ 实例
parse
: 将目标字符解析为 ‘日期’ 实例
private static void create() {
LocalTime localTime = LocalTime.now();
System.out.println("时间: " + localTime);
LocalDate localDate = LocalDate.of(2022, 1, 21);
System.out.println("日期: " + localDate);
LocalDateTime localDateTime = LocalDateTime.parse("2022-01-21 14:22:23", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println("日期和时间: " + localDateTime);
}
2. 获取相关内容
GetXxx
:
private static void get() {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("年: " + localDateTime.getYear());
System.out.println("月: " + localDateTime.getMonth());
System.out.println("日: " + localDateTime.getDayOfMonth());
System.out.println("时: " + localDateTime.getHour());
System.out.println("分: " + localDateTime.getMinute());
System.out.println("秒: " + localDateTime.getSecond());
System.out.println("纳秒: " + localDateTime.getNano());
}
- 提前或推迟或定位日期
pinus/minusXxxx
: 提前到新的 ‘日期’ , 返回新的 ‘日期’ 实例
plus/plusXxxx
: 推迟到新的 ‘日期’ , 返回新的 ‘日期’ 实例
with/withXxxx
: 定位到新的 ’日期’ , 返回新的 ‘日期’ 实例
private static void plusAndMinusAndWith() {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("源数据: " + localDateTime);
LocalDateTime plus = localDateTime.plus(100L, ChronoUnit.HOURS);
System.out.println("加 100 小时: " + plus);
LocalDateTime plusDays = localDateTime.plusDays(3L);
System.out.println("加 3 天: " + plusDays);
System.out.println("减 1 天: " + localDateTime.minus(1L, ChronoUnit.DAYS));
System.out.println("定位到当月 1 日: " + localDateTime.with(ChronoField.DAY_OF_MONTH, 1));
}
4. 格式化
format
: 根据 ‘日期’ 格式器格式化 ‘日期’
private static void format() {
LocalDateTime now = LocalDateTime.now();
System.out.println("格式化后字符串: " + now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
日 期 : 2022 − 02 − 12 \color{#00FF00}{日期:2022-02-12} 日期:2022−02−12