需要学会什么?
什么是不可变集合?
为什么要创建不可变集合?
如何创建不可变集合?
方法名称 | 说明 |
---|---|
static List of(E…elements) | 创建一个具有指定元素的List集合对象。 |
static Set of(E…elements) | 创建一个具有指定元素的Set集合对象。 |
static | 创建一个具有指定元素的Map集合对象。 |
Test.java
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// 不可变List集合 不能增加/删除/修改
List<Double> list = List.of(569.9, 700.9, 499.9, 600.0, 500.0);
// 700.9
System.out.println(list.get(1));
// [569.9, 700.9, 499.9, 600.0, 500.0]
System.out.println(list);
// 不可变Set集合 不能增加/删除/修改 不允许元素重复
Set<String> set = Set.of("白子画", "花千骨", "霓漫天");
// [花千骨, 白子画, 霓漫天]
System.out.println(set);
// 不可变Map集合 不能增加/删除/修改 不允许键重复
Map<String, Integer> map = Map.of("显示屏", 2, "主机", 1, "键盘", 1, "鼠标", 1);
// {键盘=1, 显示屏=2, 主机=1, 鼠标=1}
System.out.println(map);
}
}
什么是Stream流?
案例:体验Stream流的作用。
需求:
创建一个集合,存储多个字符串元素。
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("赵敏");
list.add("周芷若");
list.add("小昭");
list.add("殷离");
list.add("张翠山");
list.add("谢逊");
list.add("灭绝师太");
list.add("张三丰");
list.add("张中");
list.add("张士诚");
把集合中所有以”张“开头的元素存储到一个新的集合。
把”张“开头的集合中的长度为3的元素存储到一个新的集合。
遍历上一步得到的集合中的元素输出。
Test.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
// 创建集合
List<String> names = new ArrayList<>();
Collections.addAll(names, "张无忌", "赵敏", "周芷若", "小昭", "殷离", "张翠山", "谢逊", "灭绝师太", "张三丰", "张中", "张士诚");
// [张无忌, 赵敏, 周芷若, 小昭, 殷离, 张翠山, 谢逊, 灭绝师太, 张三丰, 张中, 张士诚]
System.out.println(names);
// 从集合中找出姓"张"的放到新集合
List<String> zhangList = new ArrayList<>();
for (String name : names) {
if (name.startsWith("张")) {
zhangList.add(name);
}
}
// [张无忌, 张翠山, 张三丰, 张中, 张士诚]
System.out.println(zhangList);
// 把"张"开头的集合中的长度为3的元素存储到一个新的集合
List<String> zhangThreeList = new ArrayList<>();
for (String name : zhangList) {
if (name.length() == 3) {
zhangThreeList.add(name);
}
}
// [张无忌, 张翠山, 张三丰, 张士诚]
System.out.println(zhangThreeList);
/* Stream实现*/
names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
names.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(System.out::println);
}
}
Stream流式思想的核心:
总结:
Stream流的三类方法:
Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能。
集合获取Stream流的方式:
名称 | 说明 |
---|---|
defalut Stream stream() | 获取当前集合对象的Stream流。 |
数组获取Stream流的方式:
名称 | 说明 |
---|---|
public static Stream steam(T[] array) | 获取当前数组的Stream流。 |
public static Stream of(T…values) | 获取当前数组/可变数据的Stream流。 |
Test.java
import java.util.*;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
/* Collection集合获取流 */
Collection<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();
/* Map集合获取流 */
Map<String, Integer> map = new HashMap<>();
// 键流
Stream<String> keyStream = map.keySet().stream();
// 值流
Stream<Integer> valueStream = map.values().stream();
// 键值对流(拿整体)
Stream<Map.Entry<String, Integer>> keyValueStream = map.entrySet().stream();
/* 数组获取流 */
String[] names = {"白子画", "花千骨", "杀阡陌"};
Stream<String> stringStream = Arrays.stream(names);
Stream<String> stringStream1 = Stream.of(names);
}
}
Stream流的常用API(中间操作方法):
名称 | 说明 |
---|---|
Stream filter(Predicate super T> predicate) | 用于对流中的数据进行过滤。 |
Stream limit(long maxSize) | 获取前几个元素。 |
Stream skip(long n) | 跳过前几个元素。 |
Stream distinct() | 去除流中重复的元素。依赖(hashCode()和equals()) |
static Stream concat(Stream a, Stream b) | 合并a和b两个流为一个流。 |
注意:
Test.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
// 创建集合
List<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "赵敏", "周芷若", "小昭", "殷离", "张翠山", "谢逊", "灭绝师太", "张三丰", "张中", "张士诚");
/* 对流中的数据进行过滤 */
// Stream filter(Predicate super T> var1)
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张");
}
});
list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
/* 统计元素个数 */
long size = list.stream().filter(s -> s.length() == 3).count();
System.out.println(size);
/* 获取前几个元素 */
list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(System.out::println);
/* 跳过前几个元素 */
list.stream().filter(s -> s.startsWith("张")).skip(2).forEach(System.out::println);
/* Map加工方法 */
// 给集合元素的前面都加上一个标识
list.stream().map(s -> "加工" + s).forEach(System.out::println);
// 把所有名字都加工成一个学生对象
list.stream().map(s -> new Student(s)).forEach(System.out::println);
list.stream().map(Student::new).forEach(System.out::println);
/* 合并流 */
Stream<String> stringStream = list.stream().filter(s -> s.startsWith("张"));
Stream<String> stringStream1 = Stream.of("Java1", "Java2");
// 合并
// Stream stringStreamConcat = Stream.concat(stringStream, stringStream1);
// stringStreamConcat.forEach(System.out::println);
// 合并两个不同类型的流 要用两个类型的共同父类来接
Stream<Integer> stringStream2 = Stream.of(99, 100);
Stream<Object> stringStreamConcat1 = Stream.concat(stringStream, stringStream2);
stringStreamConcat1.forEach(System.out::println);
}
}
Stream流的常见终结操作方法:
名称 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行遍历操作。 |
long count() | 返回此流中的元素数。 |
注意:终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了。
总结:
需求:
分析:
Employee.java
import java.util.List;
public class Employee {
// 姓名
private String name;
// 性别
private char sex;
// 月薪
private double salary;
// 奖金
private double bonus;
// 处罚
private String punish;
public Employee() {
}
public Employee(String name, char sex, double salary, double bonus, String punish) {
this.name = name;
this.sex = sex;
this.salary = salary;
this.bonus = bonus;
this.punish = punish;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public String getPunish() {
return punish;
}
public void setPunish(String punish) {
this.punish = punish;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sex=" + sex +
", salary=" + salary +
", bonus=" + bonus +
", punish='" + punish + '\'' +
'}';
}
}
TopPerformer.java
public class TopPerformer {
// 姓名
private String name;
// 月薪
private double salary;
public TopPerformer() {
}
public TopPerformer(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "TopPerformer{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
}
Test.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
public class Test {
// 各部门所有月收入
public static double allMoney = 0;
// 两个部门所有月收入
public static double allMoneyAll = 0;
public static void main(String[] args) {
// 开发一部
List<Employee> employeeList1 = new ArrayList<>();
employeeList1.add(new Employee("白子画", '男', 10000, 200000000, null));
employeeList1.add(new Employee("花千骨", '女', 10000, 2000, "顶撞师父"));
employeeList1.add(new Employee("杀阡陌", '男', 10000, 200000, null));
// 开发二部
List<Employee> employeeList2 = new ArrayList<>();
employeeList2.add(new Employee("张无忌", '男', 30000, 2000000, "错放陈友谅"));
employeeList2.add(new Employee("赵敏", '女', 10000, 20000, null));
employeeList2.add(new Employee("周芷若", '女', 10000, 2000, "反复无常"));
employeeList2.add(new Employee("小昭", '女', 10000, 20000, null));
employeeList2.add(new Employee("殷离", '女', 10000, 10000, null));
employeeList2.add(new Employee("张翠山", '男', 10000, 500, "冲动易怒惹人厌"));
// 最高工资的员工
// Employee topSalaryEmployee1 = employeeList1.stream().max((employee1, employee2) -> {
// return Double.compare(employee1.getSalary() * 12 + employee1.getBonus(), employee2.getSalary() * 12 + employee2.getBonus());
// }).get();
// System.out.println(topSalaryEmployee1);
//
// Employee topSalaryEmployee2 = employeeList2.stream().max((employee1, employee2) -> {
// return Double.compare(employee1.getSalary() * 12 + employee1.getBonus(), employee2.getSalary() * 12 + employee2.getBonus());
// }).get();
// System.out.println(topSalaryEmployee2);
/* 封装成优秀员工对象 */
// 封装成优秀员工对象 开发一部
TopPerformer topPerformer1 = employeeList1.stream().max(new Comparator<Employee>() {
@Override
public int compare(Employee employee1, Employee employee2) {
return 0;
}
}).map(employee -> new TopPerformer(employee.getName(), employee.getSalary() * 12 + employee.getBonus())).get();
System.out.println(topPerformer1);
// 封装成优秀员工对象 开发二部
TopPerformer topPerformer2 = employeeList2.stream().max(new Comparator<Employee>() {
@Override
public int compare(Employee employee1, Employee employee2) {
return 0;
}
}).map(employee -> new TopPerformer(employee.getName(), employee.getSalary() * 12 + employee.getBonus())).get();
System.out.println(topPerformer2);
/* 统计平均月收入 要求去掉最高和最低工资 */
// 统计平均月收入 要求去掉最高和最低工资 开发一部
employeeList1.stream().sorted(new Comparator<Employee>() {
@Override
public int compare(Employee employee1, Employee employee2) {
return Double.compare(employee1.getSalary() * 12 + employee1.getBonus(), employee2.getSalary() * 12 + employee2.getBonus());
}
}).skip(1).limit(employeeList1.size() - 2).forEach(employee -> {
// 去掉最高和最低工资后的工资总和
allMoney += (employee.getSalary() * 12 + employee.getBonus());
});
System.out.println("开发一部的平均工资是:" + allMoney / (employeeList1.size() - 2));
// 统计平均月收入 要求去掉最高和最低工资 开发二部
allMoney = 0;
employeeList2.stream().sorted(new Comparator<Employee>() {
@Override
public int compare(Employee employee1, Employee employee2) {
return Double.compare(employee1.getSalary() * 12 + employee1.getBonus(), employee2.getSalary() * 12 + employee2.getBonus());
}
}).skip(1).limit(employeeList2.size() - 2).forEach(employee -> {
// 去掉最高和最低工资后的工资总和
allMoney += (employee.getSalary() * 12 + employee.getBonus());
});
System.out.println("开发二部的平均工资是:" + allMoney / (employeeList2.size() - 2));
/* 统计2个开发部门整体的平均工资,要求去掉最高和最低工资 */
Stream<Employee> employeeStream1 = employeeList1.stream();
Stream<Employee> employeeStream2 = employeeList2.stream();
Stream<Employee> employeeStreamAll = Stream.concat(employeeStream1, employeeStream2);
employeeStreamAll.sorted(new Comparator<Employee>() {
@Override
public int compare(Employee employee1, Employee employee2) {
return Double.compare(employee1.getSalary() * 12 + employee1.getBonus(), employee2.getSalary() * 12 + employee2.getBonus());
}
}).skip(1).limit(employeeList1.size() + employeeList2.size() - 2).forEach(employee -> {
allMoneyAll += (employee.getSalary() * 12 + employee.getBonus());
});
System.out.println("2个开发部门整体的平均工资是:" + allMoneyAll / (employeeList1.size() + employeeList1.size() - 2));
}
}
Stream流的收集操作:
Stream流的收集方法:
名称 | 说明 |
---|---|
R collect(Collector collector) | 开始收集Stream流,指定收集器。 |
Collectors工具类提供了具体的收集方式:
名称 | 说明 |
---|---|
public static Collector toList() | 把元素收集到List集合中。 |
public static Collector toSet() | 把元素收集到Set集合中。 |
public static Collector toMap(Function keyMapper, Function valueMapper) | 把元素收集到Map集合中。 |
Test.java
import java.util.*;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 目标:收集Stream流的数据到 集合或数组中去。
*/
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "赵敏", "周芷若", "小昭", "殷离", "张翠山", "谢逊", "灭绝师太", "张三丰", "张中", "张士诚");
System.out.println(list);
Stream<String> stringStream1 = list.stream().filter(s -> s.startsWith("张"));
// 得到不可变集合
// System.out.println(stringStream1.toList());
// 把元素收集到List集合中
List<String> zhangList = stringStream1.collect(Collectors.toList());
// [张无忌, 张翠山, 张三丰, 张中, 张士诚]
System.out.println(zhangList);
Stream<String> stringStream2 = list.stream().filter(s -> s.startsWith("张"));
// 把元素收集到Set集合中
Set<String> zhangSet = stringStream2.collect(Collectors.toSet());
// [张翠山, 张中, 张三丰, 张无忌, 张士诚]
System.out.println(zhangSet);
Stream<String> stringStream3 = list.stream().filter(s -> s.startsWith("张"));
// 把元素收集到数组中
Object[] array = stringStream3.toArray();
// 拓展
String[] stringArray = stringStream3.toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int i) {
return new String[i];
}
});
// [张无忌, 张翠山, 张三丰, 张中, 张士诚]
System.out.println(Arrays.toString(array));
}
}
总结:
什么是异常?
为什么要学习异常?
异常体系:
Error:
Exception:java.lang包下,称为异常类,它代表程序本身可以处理的问题。
编译时异常和运行时异常:
总结:
运行时异常示例:
运行时异常:一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误。
Test.java
public class Test {
public static void main(String[] args) {
/* 数组索引越界异常:ArrayIndexOutOfBoundsException */
int[] array = {10, 20, 30};
System.out.println(array[2]);
// 日志栈 先执行的日志在下面
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// at com.javase.exceptiondemo.Test1.main(Test1.java:11)
// System.out.println(array[3]);
/* 空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错 */
String name = null;
System.out.println(name);
// System.out.println(name.length());
/* 数字操作异常:arithmeticException */
// int c = 10 / 0;
/* 类型转换异常:ClassCastException */
Object o = 23;
// String s = (String) o;
/* 数字转换异常:NumberFormatException */
String number = "23A";
Integer it = Integer.valueOf(number);
System.out.println(it + 1);
System.out.println("程序结束");
}
}
编译时异常:
编译时异常示例:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) throws ParseException {
String dateString = "2022-07-23 16:00:00";
// 创建简单日期格式化类对象:解析字符串时间成为日期对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(dateString);
System.out.println(date);
}
}
编译时异常的作用是什么:
Test.java
public class Test {
public static void main(String[] args) {
System.out.println("---程序开始---");
division(10, 5);
division(10, 0);
System.out.println("---程序结束---");
}
/**
* 除法
* @param a 被除数
* @param b 除数
*/
public static void division(int a, int b) {
System.out.println(a);
System.out.println(b);
int c = a / b;
System.out.println(c);
}
}
总结:
编译时异常的处理形式有三种:
异常处理方式一:throws
抛出异常格式:
方法 throws 异常1, 异常2, 异常3 ... {
}
规范做法:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) throws ParseException {
System.out.println("---程序开始---");
parseTime("2022-07-23 18:00:00");
System.out.println("---程序结束---");
}
private static void parseTime(String s) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(s);
System.out.println(date);
}
}
异常处理方式2:try…catch…
格式:
try {
// 监视可能出现
} catch(异常类型1 变量) {
// 处理异常
} catch(异常类型2 变量) {
// 处理异常
} ...
建议格式:
try {
// 监视可能出现
} catch(Exception e) {
// 打印异常栈信息
e.printStackTrace();
}
// Exception可以捕获处理一切异常类型!
Test.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args){
System.out.println("---程序开始---");
parseTime("2022-07-23 18:00:00");
System.out.println("---程序结束---");
}
private static void parseTime(String s) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
// 整体捕获异常
try {
date = simpleDateFormat.parse(s);
InputStream inputStream = new FileInputStream("a.jpg");
System.out.println(inputStream);
} catch (ParseException | FileNotFoundException e) {
e.printStackTrace();
}
System.out.println(date);
// 分开捕获异常
// try {
// date = simpleDateFormat.parse(s);
// } catch (ParseException e) {
// // 解析出现问题
// System.out.println("解析时间出现异常!");
// e.printStackTrace();
// // throw new RuntimeException(e);
// }
// System.out.println(date);
//
// try {
// InputStream inputStream = new FileInputStream("a.jpg");
// System.out.println(inputStream);
//
// } catch (FileNotFoundException e) {
// System.out.println("文件不存在!");
// e.printStackTrace();
// }
}
}
异常处理方式3:前两者结合
Test.java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) {
System.out.println("---程序开始---");
try {
parseTime("2022-07-24 18:00:00");
System.out.println("操作成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("操作失败!");
}
System.out.println("---程序结束---");
}
private static void parseTime(String s) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(s);
System.out.println(date);
}
}
总结:
运行时异常的处理形式:
Test.java
public class Test {
public static void main(String[] args) {
System.out.println("---程序开始---");
try {
division(10, 0);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("---程序结束---");
}
public static void division(int a, int b) {
System.out.println(a);
System.out.println(b);
int c = a / b;
System.out.println(c);
}
}
需求:
分析:
Test.java
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
try {
System.out.println("请您输入合法的价格:");
String priceStr = scanner.nextLine();
// 转成double类型的价格
double price = Double.parseDouble(priceStr);
if (price > 0) {
System.out.println("定价:" + price);
break;
} else {
System.out.println("价格必须是正数!");
}
} catch (NumberFormatException e) {
System.out.println("输入的数据不正确,请输入合法的数值!");
}
}
}
}
自定义异常的必要?
自定义异常的好处:
自定义异常的分类:
自定义编译时的异常:提醒强烈,一定要处理。
AgeIllegalException.java
/**
* 年龄非法异常
*/
public class AgeIllegalException extends Exception{
public AgeIllegalException() {
}
public AgeIllegalException(String message) {
super(message);
}
}
Test.java
/**
* 需求:认为年龄小于0岁,大于200岁就是一个异常
*
*/
public class Test {
public static void main(String[] args) {
try {
checkAge(201);
} catch (AgeIllegalException e) {
e.printStackTrace();
}
}
public static void checkAge(int age) throws AgeIllegalException {
if (age < 0 || age > 200) {
// 抛出一个异常给调用者
// throw:在方法内部直接创建一个异常对象 并从此点抛出
// throws:用在方法申明上的 抛出方法内部的异常
throw new AgeIllegalException(age + " is illegal!");
} else {
System.out.println("年龄合法:推荐商品给其购买");
}
}
}
自定义运行时异常:提醒不强烈,编译阶段不报错,运行时才可能出现。
AgeIllegalRuntimeException.java
package com.javase.exceptiondemo2;
public class AgeIllegalRuntimeException extends RuntimeException{
public AgeIllegalRuntimeException() {
}
public AgeIllegalRuntimeException(String message) {
super(message);
}
}
Test.java
/**
* 需求:认为年龄小于0岁,大于200岁就是一个异常
*
*/
public class Test {
public static void main(String[] args) {
try {
checkAgeRuntime(0);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkAgeRuntime(int age) {
if (age < 0 || age > 200) {
// 抛出一个异常给调用者
// throw:在方法内部直接创建一个异常对象 并从此点抛出
// throws:用在方法申明上的 抛出方法内部的异常
throw new AgeIllegalRuntimeException(age + " is illegal!");
} else {
System.out.println("年龄合法:推荐商品给其购买");
}
}
}