文章目录
学习日记(Stream 流、异常处理案例、日志框架)
一、Stream 流
1. 概述
在 Java 8 中,得益于 Lambda 表达式所带来的函数式编程,引入了一个全新的 Stream 流概念。
目的:用于简化集合和数组操作的 API。
核心思想:先得到集合或数组的 Stream 流(就是一跟传送带)—> 把元素放上去 —> 然后用 Stream 流简化的 API 来方便地操作元素。
需求:输出同学中姓”王“并且名字为三个字的同学。
2. 获取 Stream 流
获取 Stream 流是用 Stream 流操作集合或数组的第一步,获取 Stream 流的 API 如下。
集合或数组 | 方法名 | 说明 |
---|---|---|
Collection 或 Map 集合 | default Stream stream() | 集合获取 Stream 流 |
数组 | public static Stream stream(T[] array) | 数组获取 Stream 流的方法一(Arrays 类的方法) |
数组 | public static Stream of(T… values) | 数组获取 Stream 流的方法二(Stream 的方法) |
注意:数组获取 Stream 流的方法二其实和方法一相同,但是方法一的参数必须是数组,而方法二的参数是可变参数(可以直接传入元素也可以传入数组)。
3. 常用 API
中间操作的方法(非终结方法) | 说明 |
---|---|
Stream filter(Predicate<? super T> predicate) | 对流中的数据进行过滤(筛选) |
Stream limit(long maxSize) | 提取前几个元素 |
Stream skip(long n) | 跳过前几个元素 |
Stream map(Function<? super T, ? extends R> mapper) | 对流中的数据进行加工 |
Stream distinct() | 去除流中重复的元素,依赖 hashCode 和 equals 方法 |
public static Stream concat(Stream<? extends T> a, Stream<? extends T> b) | 合并 a 流和 b 流为一个流,此时 a 流和 b 流会关闭 |
终结操作方法 | 说明 |
---|---|
long count() | 返回此流中的元素数,返回值类型为 long |
void forEach(Consumer<? super T> action) | 对此流中的每个元素进行遍历 |
注意:
- 中间方法也称为非终结方法,调用完成之后会返回新的 Stream 流,可以继续使用,支持链式编程。
- 终结方法调用后,流就无法继续使用了,原因是不会返回 Stream 了。
- 在 Stream 流中无法直接修改原集合或原数组的数据。
- 在合并流(concat)时,只能同时合并两个流,并且合并之后,原先两个流会关闭。
- 流只能使用一次!
示例
运行结果
4. 综合应用
需求:给定 5 个员工信息,包括姓名、性别、工资信息,要求:
- 筛选出最高工资的员工信息,封装成优秀员工对象(Topperformer);
- 统计出所有员工的平均工资,要求去掉最高和最低工资。
用到流的方法 | 说明 |
---|---|
Optional max(Comparator<? super T> comparator) | 自定义比较规则,先排序,然后剩最大值的对象 |
public T get() | 从流中取对象 |
Stream sorted(Comparator<? super T> comparator) | 自定义比较规则,排序 |
运行结果
package com.residue.stream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class StreamDemo04 {
/*
需求:给定 5 个员工信息,包括姓名、性别、工资信息,要求:
- 筛选出最高工资的员工信息,封装成优秀员工对象(Topperformer);
- 统计出所有员工的平均工资,要求去掉最高和最低工资。
*/
public static double sumSalary = 0;
public static void main(String[] args) {
Employee e1 = new Employee("张一", '男', 17008.89);
Employee e2 = new Employee("刘二", '女', 27005.12);
Employee e3 = new Employee("李三", '男', 19210.95);
Employee e4 = new Employee("赵四", '女', 18312.24);
Employee e5 = new Employee("孙五", '男', 25629.71);
List<Employee> list1 = new ArrayList<>();
Collections.addAll(list1, e1, e2, e3, e4, e5);
System.out.println(list1);
System.out.println("===========================================");
//需求一:筛选出最高工资的员工信息,封装成优秀员工对象(Topperformer)。
Topperformer topperformer = list1.stream().
max((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary())).
map(s -> new Topperformer(s.getName(), s.getSex(), "Top")).
get();
System.out.println(topperformer);
System.out.println("===========================================");
//需求二:统计出所有员工的平均工资,要求去掉最高和最低工资。
list1.stream().sorted((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary())).
skip(1).limit(list1.size() - 2).
forEach(s -> {
sumSalary += s.getSalary();
});
BigDecimal sumSalary1 = BigDecimal.valueOf(sumSalary);
BigDecimal num = BigDecimal.valueOf(list1.size() - 2);
BigDecimal result = sumSalary1.divide(num, 2, RoundingMode.HALF_UP);
double average = result.doubleValue();
System.out.println("员工的平均工资为(去掉最低和最高):" + average);
}
}
5. 收集 Stream 流
含义:就是把 Stream 流操作后的结果数据转回到集合或数组中。
注意:Stream 流是方便操作集合或数组的手段,而集合或数组才是目的。
方法:
-
把流 stream1 中的元素收集到 List 集合中:
List<Integer> collectList = stream1.collect(Collectors.toList());
。 -
把流 stream2 中的元素收集到 Set 集合中:
Set<Integer> collectSet = stream2.collect(Collectors.toSet());
。 -
把流 stream3 中的元素收集到数组中,注意返回值类型为 Object 数组:
Object[] collectArray = stream3.toArray();
。 -
把流 stream4 中的元素收集到数组中,注意返回值类型为 Integer 数组:
Integer[] collectArray1 = stream3.toArray(s -> new Integer[s]);
。
二、异常处理案例
需求:键盘录入价格,直到价格的格式正确:必须为数字,必须大于 0。
写法一:直接把输入不是数字和输入数字为负数的情况排除。
写法二:用异常处理
三、日志框架
1. 概述
程序中的日志可以用来记录程序运行过程中的信息,并可以进行永久存储。
输出语句与日志技术对比:
输出语句 | 日志技术 | |
---|---|---|
输出位置 | 只能是控制台 | 可以将日志信息选择性地记录到控制台、文件或者数据库中 |
取消日志 | 需要修改代码,灵活性较差 | 可以随时以开关的形式控制是否记录日志,不需要修改代码,灵活性比较好 |
多线程 | 性能较差 | 性能较好 |
2. 日志技术体系
日志规范指一些接口,提供给日志的实现框架设计的标准。(相当于接口)
日志规范接口有:Commons Logging
(简称:JCL)和 Simle Logging Facade for Java
(简称:slf4j)。
日志实现框架指已经做好的日志记录实现代码,可以直接拿来使用。(相当于实现类)
日志实现框架有:Log4J
和 JUL
和 Logback
等等。
3. Logback 日志框架
官网(点此进入):https://logback.qos.ch/index.html
。
Logback 日志框架有三个模块:logback-core、logback-classic 和 logback-access。
- logback-core:必须有,为其他两个模块奠定了基础;
- logback-classic:是 Log4J 的一个改良版本,完整地实现了 Log4J API。
- logback-access:与Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志功能。
Logback 日志框架的后续内容由于部分原因以后再学吧!
注意:
- Lambda 表达式在 Stream 流的作用!
- 在合并流(concat)时,只能同时合并两个流,并且合并之后,原先两个流会关闭。
- 在使用终结方法后,流会关闭,不能再调用方法。
- Java 中局部内部类和匿名内部类访问的局部变量必须由 final 修饰。
- 流只能使用一次!
- 一个 haxNextInt 应该对应一个 nextInt,这样可以使得后面重新输入,也可以只有 nextInt。