文章目录
- 黑马程序员Java教程学习笔记(五)
- 日期时间:Date、SimpleDateFormat、Calendar
- JDK8开始新增日期API
- 包装类
- 正则表达式
- Arrays类
- 选择排序、二分查找
- Lambda表达式
- 集合概述、Collection集合的体系特点
- Collection常用API、遍历方式、存储自定义类型对象
- 常见数据结构
- List系列集合、集合的并发修改异常问题
- 泛型深入、自定义泛型、泛型通配符、上下限
- Set系列集合、Collection体系的总结
- 可变参数、集合操作的工具类Collections
- 斗地主游戏
- Map集合概述、API、遍历方式
- Map集合案例、其他实现类
- 集合嵌套
- 创建不可变集合
- Stream流体系
- 异常概述、体系
- 异常的处理机制
- 异常的强大演示、自定义异常
- 日志概述、日志技术体系
- Logback日志框架的快速入门、日志级别设置等
- 影院系统开发
黑马程序员Java教程学习笔记(五)
日期时间:Date、SimpleDateFormat、Calendar
package com.mochu.d1_date;
import java.util.Date;
public class DateDemo1 {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
// 获取毫秒级时间戳
long t = d.getTime();
System.out.println(t);
System.out.println("-----------------");
Date d1 = new Date();
System.out.println(d1);
// 当前时间往后走一小时121秒
long time = System.currentTimeMillis();
time += (60 * 60 + 121) * 100;
// 把时间戳转换成日期
Date d2 = new Date(time);
System.out.println(d2);
Date d3 = new Date();
d3.setTime(time);
System.out.println(d3);
}
}
package com.mochu.d2_simpledateformat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
// 格式化日期对象
SimpleDateFormat sdf = new SimpleDateFormat("YYYY年MM月DD日 HH:mm:ss EEE a");
String rs = sdf.format(d);
System.out.println(rs);
System.out.println("---------------------------");
// 格式化时间戳
long time = System.currentTimeMillis() + 121 * 1000;
String rs2 = sdf.format(time);
System.out.println(rs2);
System.out.println("---------------------------");
// 解析时间
}
}
package com.mochu.d2_simpledateformat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleFormatDemo {
public static void main(String[] args) throws ParseException {
// 解析字符串时间为日期对象
String date = "2021年08月06日 11:11:11";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date d = sdf.parse(date);
long time = d.getTime() + (2L * 24 * 60 * 60 + 14 * 60 * 60 + 49 * 60 + 6) * 1000;
System.out.println(sdf.format(time));
}
}
package com.mochu.d2_simpledateformat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatTest {
public static void main(String[] args) throws ParseException {
String startTime = "2021-11-11 00:00:00";
String endTime = "2021-11-11 00:10:00";
String xiaoJia = "2021-11-11 00:03:47";
String xiaoPi = "2021-11-11 00:10:11";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = sdf.parse(startTime);
Date d2 = sdf.parse(endTime);
Date d3 = sdf.parse(xiaoJia);
Date d4 = sdf.parse(xiaoPi);
if(d3.after(d1) && d3.before(d2)) {
System.out.println("小贾秒杀成功");
}else {
System.out.println("小贾秒杀失败");
}
if(d4.after(d1) && d4.before(d2)) {
System.out.println("小皮秒杀成功");
}else {
System.out.println("小皮秒杀失败");
}
}
}
Caledar概述:
- Calendar代表了系统此时日期对应的日历对象
- Calendar是一个抽象类,不能直接创建对象
package com.mochu.d3_calendar;
import java.util.Calendar;
import java.util.Date;
public class Test {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
System.out.println(cal);
// 获取其中某个字段的信息
int year = cal.get(Calendar.YEAR);
System.out.println(year);
int month = cal.get(Calendar.MONTH) + 1;
System.out.println(month);
int day = cal.get(Calendar.DAY_OF_YEAR);
System.out.println(day);
// 修改其中的某个字段,一般不会修改
// cal.set(Calendar.HOUR, 12);
// System.out.println(cal);
// 为某个字段增加/减少值
cal.add(Calendar.DAY_OF_YEAR, 64);
cal.add(Calendar.MINUTE, 59);
// 拿到此日期的对象
Date d = cal.getTime();
System.out.println(d);
// 拿到此刻时间的毫秒值(时间戳)
long time = cal.getTimeInMillis();
System.out.println(time);
}
}
JDK8开始新增日期API
package com.mochu.d4_jdk8time;
import java.time.LocalDate;
import java.time.Month;
public class Demo01LocalDate {
public static void main(String[] args) {
// 获取本地日期对象
LocalDate nowDate = LocalDate.now();
System.out.println("今天的日期:" + nowDate);
int year = nowDate.getYear();
System.out.println("Year: " + year);
int month = nowDate.getMonthValue();
System.out.println("Month:" + month);
int day = nowDate.getDayOfMonth();
System.out.println("Day: " + day);
// 今年的第几天
int dayOfYear = nowDate.getDayOfYear();
System.out.println("Day of year: " + dayOfYear);
// 星期
System.out.println(nowDate.getDayOfWeek());
System.out.println(nowDate.getDayOfWeek().getValue());
// 月份
System.out.println(nowDate.getMonth());
System.out.println(nowDate.getMonth().getValue());
LocalDate bt = LocalDate.of(1921, 11, 11);
System.out.println(bt);
System.out.println(LocalDate.of(1991, Month.NOVEMBER, 11));
}
}
package com.mochu.d4_jdk8time;
import java.time.LocalTime;
public class Demo02LocalTime {
public static void main(String[] args) {
// 获取本地事件对象
LocalTime nowTime = LocalTime.now();
System.out.println("今天的时间:" + nowTime);
// 时
int hour = nowTime.getHour();
System.out.println("Hour: " + hour);
// 分
int minute = nowTime.getMinute();
System.out.println("Minute: " + minute);
// 秒
int second = nowTime.getSecond();
System.out.println("Second: " + second);
// 纳秒
int nano = nowTime.getNano();
System.out.println("nano: " + nano);
System.out.println("---------------------");
System.out.println(LocalTime.of(8, 20)); // 时分
System.out.println(LocalTime.of(8, 20, 30)); // 时分秒
System.out.println(LocalTime.of(8, 20, 30, 150)); // 时分秒纳秒
LocalTime mTime = LocalTime.of(8, 20, 30, 150);
}
}
package com.mochu.d4_jdk8time;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Demo03LocalDateTime {
public static void main(String[] args) {
// 日期 时间
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("今天是:" + nowDateTime);
System.out.println("年:" + nowDateTime.getYear());
System.out.println("月:" + nowDateTime.getMonthValue());
System.out.println("日:" + nowDateTime.getDayOfMonth());
System.out.println("时:" + nowDateTime.getHour());
System.out.println("分:" + nowDateTime.getMinute());
System.out.println("秒:" + nowDateTime.getSecond());
System.out.println("纳秒:" + nowDateTime.getNano());
// 日,当年的第几天
System.out.println("Day Of Year: " + nowDateTime.getDayOfYear());
// 星期
System.out.println("星期:" + nowDateTime.getDayOfWeek());
System.out.println("星期:" + nowDateTime.getDayOfWeek().getValue());
// 月份
System.out.println("月份:" + nowDateTime.getMonth());
System.out.println("月份:" + nowDateTime.getMonth().getValue());
LocalDate ld = nowDateTime.toLocalDate();
System.out.println(ld);
LocalTime lt = nowDateTime.toLocalTime();
System.out.println(lt.getHour());
System.out.println(lt.getMinute());
System.out.println(lt.getSecond());
}
}
package com.mochu.d4_jdk8time;
import java.time.LocalDate;
import java.time.LocalTime;
public class Demo04UpdateTime {
public static void main(String[] args) {
LocalTime nowTime = LocalTime.now();
System.out.println("当前时间:" + nowTime);
System.out.println("一小时前:" + nowTime.minusHours(1));
System.out.println("一小分钟前:" + nowTime.minusMinutes(1));
System.out.println("一小秒钟前:" + nowTime.minusSeconds(1));
System.out.println("一小纳秒前:" + nowTime.minusNanos(1));
System.out.println("一小时后:" + nowTime.plusHours(1));
System.out.println("一分钟后:" + nowTime.plusMinutes(1));
System.out.println("一秒钟后:" + nowTime.plusSeconds(1));
System.out.println("一纳秒后:" + nowTime.plusNanos(1));
LocalDate myDate = LocalDate.of(2018, 9, 5);
LocalDate nowDate = LocalDate.now();
}
}
package com.mochu.d4_jdk8time;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Date;
public class Demo05Instant {
public static void main(String[] args) {
Instant instant = Instant.now();
System.out.println(instant);
// 输出本机默认时间
Instant instant1 = Instant.now();
System.out.println(instant1.atZone(ZoneId.systemDefault()));
// 返回Date对象
Date date = Date.from(instant);
System.out.println(date);
Instant i2 = date.toInstant();
System.out.println(i2);
}
}
package com.mochu.d4_jdk8time;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Demo06DateTimeFormat {
public static void main(String[] args) {
// 本地此刻、日期对象
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
// 解析 格式化器
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EEE a");
// 正向格式化
System.out.println(dtf.format(ldt));
// 逆向格式化
System.out.println(ldt.format(dtf));
//解析字符串时间
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dateStr = "2019-11-11 11:11:11";
LocalDateTime ldt1 = LocalDateTime.parse(dateStr, dtf1);
System.out.println(ldt1);
System.out.println(ldt1.getDayOfYear());
}
}
package com.mochu.d4_jdk8time;
import java.time.LocalDate;
import java.time.Period;
public class Demo07Period {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println(today);
LocalDate birthDate = LocalDate.of(1998, 10, 13);
System.out.println(birthDate);
Period period = Period.between(birthDate, today); //第二个参数减第一个参数
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
}
}
package com.mochu.d4_jdk8time;
import java.time.Duration;
import java.time.LocalDateTime;
public class Demo08Duration {
public static void main(String[] args) {
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
LocalDateTime birthDate = LocalDateTime.of(2023, 03, 14, 20, 00, 00);
System.out.println(birthDate);
Duration duration = Duration.between(today, birthDate);
System.out.println(duration.toDays());
System.out.println(duration.toHours());
System.out.println(duration.toMinutes());
System.out.println(duration.toMillis());
System.out.println(duration.toNanos());
}
}
package com.mochu.d4_jdk8time;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class Demo09ChronoUnit {
public static void main(String[] args) {
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
LocalDateTime birthDate = LocalDateTime.of(2023, 03, 14, 20, 00, 00);
System.out.println(birthDate);
System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthDate, today));
System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthDate, today));
System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthDate, today));
System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthDate, today));
System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthDate, today));
System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthDate, today));
System.out.println("相差的秒数:" + ChronoUnit.SECONDS.between(birthDate, today));
System.out.println("相差的毫秒数:" + ChronoUnit.MILLIS.between(birthDate, today));
System.out.println("相差的微妙数:" + ChronoUnit.MICROS.between(birthDate, today));
System.out.println("相差的纳秒数:" + ChronoUnit.NANOS.between(birthDate, today));
System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthDate, today));
System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthDate, today));
System.out.println("相差的世纪(百年)数:" + ChronoUnit.CENTURIES.between(birthDate, today));
System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthDate, today));
System.out.println("相差的纪元数:" + ChronoUnit.ERAS.between(birthDate, today));
}
}
包装类
自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量。
自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量。
包装类的特有功能:
- 包装类的变量的默认值可以是null,容错率高。
- 可以把基本类型的数据转换成字符串类型(用处不大)
– 调用toString()
方法得到字符串结果
– 调用Integer.toString
(基本类型的数据) - 可以把字符串类型的数值转换成真实的数据类型
–integer.parseInt("字符串类型的整数")
–Double.parseDouble("字符串类型的浮点数")
package com.mochu.d5_integer;
public class Test {
public static void main(String[] args) {
int a = 10;
Integer a1 = 11;
Integer a2 = a; // 自动装箱
System.out.println(a);
System.out.println(a1);
Integer it = 100;
int it1 = it; // 自动拆箱
System.out.println(it1);
double db = 8.9;
Double db1 = db;
double db2 = db1;
System.out.println(db2);
Integer age = null;
System.out.println("------------------");
// 包装类可以把基本类型的数据转换成字符串类型
Integer i3 = 23;
String rs = i3.toString();
System.out.println(rs + 1);
String rs1 = Integer.toString(i3);
System.out.println(rs + 1);
String rs2 = i3 + "";
System.out.println(rs2 + 1);
System.out.println("------------------");
String number = "23";
// 转换成整数
// int age1 = Integer.parseInt(number);
int age1 = Integer.valueOf(number);
System.out.println(age1 + 1);
// 转换成小数
String number1 = "59.5";
// double score = Double.parseDouble(number1);
double score = Double.valueOf(number1);
System.out.println(score + 0.5);
}
}
正则表达式
package com.mochu.d6_regex;
public class RegexDemo {
public static void main(String[] args) {
// 匹配QQ号
System.out.println(checkQQ("2392517666"));
}
public static boolean checkQQ(String qq) {
return qq != null && qq.matches("\\d{6,20}");
}
}
package com.mochu.d6_regex;
public class RegexDemo {
public static void main(String[] args) {
System.out.println("a".matches("[abc]"));
System.out.println("z".matches("[abc]"));
System.out.println("a".matches("[^abc]"));
System.out.println("z".matches("[^abc]"));
System.out.println("a".matches("\\d"));
System.out.println("3".matches("\\d"));
System.out.println("333".matches("\\d"));
System.out.println("z".matches("\\w"));
System.out.println("2".matches("\\w"));
System.out.println("21".matches("\\w"));
System.out.println("你".matches("\\w"));
System.out.println("你".matches("\\W"));
System.out.println("123456".matches("\\w{6,}"));
System.out.println("1234".matches("\\w{6,}"));
System.out.println("a6Hv".matches("[a-zA-Z0-9]{4}"));
System.out.println("8_f3".matches("[a-zA-Z0-9]{4}"));
System.out.println("23dF".matches("[\\w&&[^_]]{4}"));
System.out.println("23_F".matches("[\\w&&[^_]]{4}"));
}
}
package com.mochu.d6_regex;
import java.util.Scanner;
public class RegexDemo {
public static void main(String[] args) {
// 匹配手机号码 邮箱 电话号码
matchTell();
}
public static void matchPhoneNnumber(){
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入您的手机号:");
String phonenum = sc.next();
if(phonenum.matches("1[3-9]\\d{9}")) {
System.out.println("手机号码格式正确");
break;
}else {
System.out.println("手机号码格式有误");
}
}
}
public static void matchEmail() {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入您的邮箱:");
String email = sc.next();
if(email.matches("\\w{1,}@[a-zA-Z0-9]{2,}(\\.[a-zA-Z0-9]{2,}){1,}")) {
System.out.println("邮箱格式正确");
break;
}else {
System.out.println("邮箱格式有误");
}
}
}
public static void matchTell() {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入您的电弧号码:");
String tellNum = sc.next();
if(tellNum.matches("0\\d{2,6}-?\\d{5,20}")) {
System.out.println("电话号码格式正确");
break;
}else {
System.out.println("电话号码格式有误");
}
}
}
}
package com.mochu.d6_regex;
public class RegexDemo {
public static void main(String[] args) {
String name = "末初gdg末初69ga末初ohow";
String[] arrs = name.split("\\w+");
for (int i = 0; i < arrs.length; i++) {
System.out.println(arrs[i]);
}
String name2 = name.replaceAll("\\w+", " ");
System.out.println(name2);
}
}
Arrays类
package com.mochu.d7_arrays;
import java.util.Arrays;
public class ArraysDemo {
public static void main(String[] args) {
int arr[] = {10, 24, 7, 89, 51};
// 打印输出
System.out.println(Arrays.toString(arr));
// 数组排序(升序)
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
// 二分搜索(前提必须先排序),返回不存在元素的规律:-(应该插入的位置索引 + 1)
int index = Arrays.binarySearch(arr, 51);
System.out.println(index);
}
}
package com.mochu.d7_arrays;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysDemo02 {
public static void main(String[] args) {
// 子定义数组的排序规则:Comparator比较器对象
// 降序
Integer[] ages = {11, 92, 21, 7, 45, 22, 56, 31};
/**
* 参数一:被排序的数组,引用类型的数组
* 参数二:匿名内部类对象,代表一个比较器对象
*/
Arrays.sort(ages, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// 制定比较规则
// if(o1 > o2) {
// return 1;
// }else if(o1 < o2){
// return -1;
// }
// return 0;
// return o1 - o2; // 默认升序
return - (o1 - o2); // 降序
}
});
System.out.println(Arrays.toString(ages));
Student[] students = new Student[3];
students[0] = new Student("mochu7", 21, 175.5);
students[1] = new Student("Slevin", 18, 182.5);
students[2] = new Student("Shinn", 25, 165.5);
System.out.println(Arrays.toString(students));
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 制定比较规则
// return o1.getAge() - o2.getAge(); // 按照年龄升序排序
// return o2.getAge() - o1.getAge(); // 按照年龄降序
// return Double.compare(o1.getHeight(), o2.getHeight()); // 按照身高升序
return Double.compare(o2.getHeight(), o1.getHeight()); // 按照身高降序
}
});
System.out.println(Arrays.toString(students));
}
}
选择排序、二分查找
package com.mochu.d8_binsearch;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr = {5, 1, 3, 2};
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
if(arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
package com.mochu.d8_binsearch;
public class Test {
public static void main(String[] args) {
int[] arr = {10, 14, 16, 25, 28, 30, 35, 88, 100};
System.out.println(binarySearch(arr, 35));
System.out.println(binarySearch(arr, 350));
}
/**
* 二分法查找
* @param arr 排序过后的数组
* @param data 要找的数据
* @return
*/
public static int binarySearch(int[] arr, int data) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int midIndex = (left + right) / 2;
if(data > arr[midIndex]) {
left = midIndex + 1;
}else if(data < arr[midIndex]) {
right = midIndex - 1;
}else {
return midIndex;
}
}
return -1;
}
}
Lambda表达式
-
Lambda
表达式是JDK8开始后的一种新语法形式。 - 作用:简化匿名内部类的代码写法。
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码
}
注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式
函数式接口:
- 首先必须是接口,其次接口中有且仅有一个抽象方法的形式
- 通常会在接口上加上一个
@FunctionalInterface
注解,标记该接口必须是满足函数式接口
package com.mochu.d9_Lambda;
public class LambdaDemo {
public static void main(String[] args) {
// Swimming s1 = new Swimming() {
// @Override
// public void swim() {
// System.out.println("Swimming...");
// }
// };
// 匿名类简化
Swimming s2 = () -> {
System.out.println("Swimming...");
};
go(s2);
// go(new Swimming() {
// @Override
// public void swim() {
// System.out.println("Swimming");
// }
// });
go(() -> {
System.out.println("Swimming");
});
}
public static void go(Swimming s){
s.swim();
}
}
@FunctionalInterface // 一旦加上这个注解则必须是函数式接口,里面只能有一个抽象方法
interface Swimming() {
void swim();
}
Lambda表达式简化Comparator接口的匿名形式
Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化)
- 参数类型可以省略不写
- 如果只有一个参数,参数类型可以省略,同时
()
也可以省略 - 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号
- 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写,此时,如果这行代码是
return
语句,必须省略return
不写,同时也必须省略;
不写
集合概述、Collection集合的体系特点
集合和数组都是容器
- 数组定义完成并启动后,类型确定、长度固定
- 数组在进行增删数据操作的时候,数组是不太合适的,增删数据都需要放弃原有数组或者移位
数组适合业务数据个数固定的,且都是同一批数据类型的时候,可以采取定义数组存储
集合是Java中存储对象数据的一种容器
- 集合的大小不固定、启动后可以动态变化,类型也可以选择不固定
- 集合非常适合元素的增删操作
注意:集合中只能存储引用类型的数据,如果要存储基本类型数据需要包装类
集合分为以下两类:
- Collection单列集合,每个元素(数据)只包含一个值
- Map双列集合,每个元素包含两个值(键值对)
集合对于泛型的支持
- 集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型
注意:集合和泛型都只能支持引用数据类型,不支基本数据类型,所以集合中存储的元素都认为是对象。
package com.mochu.d1_collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class CollectionDemo01 {
public static void main(String[] args) {
// List体系特点:有序、可重复、有索引
Collection list = new ArrayList();
list.add("java");
list.add("java");
list.add("python");
list.add("php");
System.out.println(list);
// Set体系特点:无序、不重复、无索引
Collection set = new HashSet();
set.add("java");
set.add("java");
set.add("python");
set.add("php");
System.out.println(set);
System.out.println("-----------------");
Collection<String> list2 = new ArrayList<>();
list2.add("mochu7");
list2.add("slevin");
// 集合和泛型都只能支持引用类型
Collection<Integer> list3 = new ArrayList<>();
list3.add(23);
list3.add(100);
Collection<Double> list4 = new ArrayList<>();
list4.add(59.9);
}
}
Collection常用API、遍历方式、存储自定义类型对象
package com.mochu.d2_collection_api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("Java");
list.add("HTML");
list.add("PHP");
list.add("Python");
System.out.println(list);
// list.clear();
// System.out.println(list);
System.out.println(list.isEmpty());
System.out.println(list.size());
System.out.println(list.contains("Java"));
list.remove("PHP");
System.out.println(list);
Object[] arr = list.toArray();
System.out.println("数组:" + Arrays.toString(arr));
Collection<String> c1 = new ArrayList<>();
c1.add("java");
c1.add("slevin");
Collection<String> c2 = new ArrayList<>();
c2.add("mochu7");
c1.addAll(c2);
System.out.println(c1);
}
}
Collection集合的遍历方式
方式一:迭代器
package com.mochu.d2_collection_api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("Java");
list.add("HTML");
list.add("PHP");
list.add("Python");
Iterator<String> it = list.iterator();
// String ele = it.next();
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
while(it.hasNext()) {
String ele = it.next();
System.out.println(ele);
}
}
}
第二种:foreach遍历/增强for循环
增强for循环:
- 增强for循环既可以遍历集合也可以遍历数组
- JDK5之后出现的,其内部原理是一个
iterator
迭代器,遍历集合相当于是迭代器的简化写法 - 实现
iterable
接口的类才可以使用迭代器和增强for,Collection
接口已经实现了Iterable接口
格式
for(元素数据类型 变量名: 数组或者Collection集合) {
// 在此处使用变量即可,该变量就是元素
}
package com.mochu.d2_collection_api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("Java");
list.add("HTML");
list.add("PHP");
list.add("Python");
for(String ele: list) {
System.out.println(ele);
}
double[] scores = {100.0, 99.5, 59.5};
for (double score : scores) {
System.out.println(score);
}
}
}
第三种:Lambda表达式
package com.mochu.d2_collection_api;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("Java");
list.add("HTML");
list.add("PHP");
list.add("Python");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("------------------");
list.forEach(s -> {
System.out.println(s);
});
System.out.println("------------------");
list.forEach(s -> System.out.println(s));
System.out.println("------------------");
list.forEach(System.out::println);
}
}
package com.mochu.d3_collection_object;
public class Movie {
private String name;
private double score;
private String actor;
public Movie() {
}
public Movie(String name, double score, String actor) {
this.name = name;
this.score = score;
this.actor = actor;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
}
package com.mochu.d3_collection_object;
import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main(String[] args) {
Collection<Movie> movies = new ArrayList<>();
movies.add(new Movie("《流浪地球2》", 9.5, "吴京、刘德华"));
movies.add(new Movie("《唐人街探案》", 8.5, "王宝强、刘昊然"));
movies.add(new Movie("《刺杀小说家》", 8.7, "雷佳音、杨幂"));
for (Movie movie : movies) {
System.out.println("电影名称:" + movie.getName());
System.out.println("电影评分:" + movie.getScore());
System.out.println("电影主演:" + movie.getActor());
}
}
}
常见数据结构
数据结构、栈、队列
数据结构概述:
- 数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的
- 通常情况下、精心选择的数据结构可以带来更高的运行或者存储效率
数据进入栈模型的过程称为:压/进栈
数据离开栈模型的过程称为:弹/出栈
栈数据结构的执行特点:后进先出、先进后出
队列数据结构的执行特点:先进先出、 后进后出
数据从后端进入队列模型的过程称为:入队列
数据从前端离开队列模型的过程称为:出队列
常见数据结构之数组
数据结构的特点
- 查询速度快:查询数据通过地址值和索引定位、查询任意数据耗时相同。(元素在内存中是连续存储的)
- 删除效率低:要将原始数据删除、同时后面每个数据迁移
- 添加效率极低:添加位置后的每个数据后移、再添加元素
数据查询数据:起始地址 + 偏移地址
综上所述:数组是一种根据索引查询快、增删慢的模型
常见数据结构之链表
- 链表中的元素是在内存中不连续存储的,每个元素节点包含数据值和下一个元素的地址
链表的特点:
- 链表查询慢:无论查询哪个数据都要从头开始找
- 链表增删较快
链表是一种查询慢、增删快(相对数组)的模型
链表分为:
- 单项链表:只能从前往后找
- 双向链表:可以从前往后也可以从后往前找
双链表增删中间的数据不一定快、但增删首尾的数据很快
常见数据结构之二叉树
常见数据结构之红黑树
- 红黑树是一种平衡的二叉查找树
- 1972年出现,当时被称为“平衡二叉B树”,1978年被修改为如今的“红黑树”
- 每一个节点可以是红或者黑;红黑树不是通过高度平衡的,它的平衡是通过“红黑规则”进行实现的
List系列集合、集合的并发修改异常问题
List集合特点、特有API
List系列集合特点:
- ArrayList、LinekdList: 有序、可重复、有索引
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
package com.mochu.d4_collection_list;
import java.util.ArrayList;
import java.util.List;
public class ListDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("python");
list.add("php");
list.add(2, "html");
System.out.println(list);
list.remove(2);
System.out.println(list);
System.out.println(list.get(2));
// 修改指定索引的值
System.out.println(list.set(1, "go"));
System.out.println(list);
}
}
List集合遍历
- 迭代器
- 增强for循环
- Lambda表达式
- for循环(因为List集合存在索引)
package com.mochu.d4_collection_list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("python");
list.add("php");
list.add("go");
list.add("html");
// for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
// 增强for循环 foreach
for(String ele : list){
System.out.println(ele);
}
// Lambda表达式
list.forEach(s -> {
System.out.println(s);
});
}
}
package com.mochu.d4_collection_list;
import java.util.LinkedList;
public class ListDemo01 {
public static void main(String[] args) {
// LinkedList可以完成队列结构、栈结构(双链表)
// 栈
LinkedList<String> stack = new LinkedList<>();
// 压栈、入栈
stack.addFirst("第1颗子弹");
// stack.push();
stack.addFirst("第2颗子弹");
stack.addFirst("第3颗子弹");
stack.addFirst("第4颗子弹");
stack.addFirst("第5颗子弹");
System.out.println(stack);
System.out.println("---------------");
// 出栈、弹栈
System.out.println(stack.removeFirst());
// System.out.println(stack.pop());
System.out.println(stack.removeFirst());
System.out.println(stack.removeFirst());
System.out.println(stack);
System.out.println("-------------------");
// 队列
LinkedList<String> queue = new LinkedList<>();
// 入列
queue.addLast("1号");
queue.addLast("2号");
queue.addLast("3号");
queue.addLast("4号");
queue.addLast("5号");
// 出列
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue);
}
}
集合的并发修改异常问题
package com.mochu.d4_collection_list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("python");
list.add("php");
list.add("java");
list.add("go");
list.add("html");
list.add("java");
System.out.println(list);
// 删除全部的Java信息
// 迭代器遍历删除
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String ele = it.next();
if(ele.equals("java")) {
// list.remove("java") // 会后移导致报错
it.remove(); // 使用迭代器删除当前所在元素,不会后移
}
}
System.out.println(list);
// for循环遍历删除也会存在后移问题,但是可以通过逆序遍历删除或者每次删除一次指针前移一下
// 逆序
// for (int i = list.size() - 1; i >= 0; i--) {
// String ele = list.get(i);
// if(ele.equals("java")) {
// list.remove("java");
// }
// }
// 每次删除后索引前移一位
for (int i = 0; i < list.size(); i++) {
String ele = list.get(i);
if(ele.equals("java")) {
list.remove("java");
i--;
}
}
}
}
泛型深入、自定义泛型、泛型通配符、上下限
泛型的概述和优势
- 泛型:是JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
- 泛型的格式:
<数据类型>;
注意:泛型只能支持引用数据类型 - 集合体系的全部接口和实现类都是支持泛型的使用的
泛型的好处:
- 统一数据类型
- 把运行时期的问题提前到编译期间,避免了强制类型转换可能出现的异常
自定义泛型类
泛型类的概述
- 定义类时同时定义了泛型的类就是泛型类
- 泛型类的格式:
修饰符 class 类名<泛型变量>{}
- 此处泛型变量
T
可以随便写为任意标识,常见的如E
、T
、K
、V
等 - 作用:编译阶段可以指定数据类型,类似于集合的作用
泛型类的原理:把出现泛型变量的地方全部替换成传输的真实数据类型
自定义泛型方法
泛型方法的概述:
- 定义方法时同时定义了泛型的方法就是泛型方法
- 泛型方法的格式:
修饰符 <泛型变量> 方法返回值 方法名称(形参列表){}
作用:方法中可以使用泛型接受一切实际类型的参数,方法更具备通用性
package com.mochu.d6_genericity_class;
public class Test {
public static void main(String[] args) {
Integer[] ages = {10, 20, 30, 40, 50};
String[] names = {"mochu7", "slevin", "shinn"};
printArray(ages);
printArray(names);
}
public static <T> void printArray(T[] arr) {
if(arr != null) {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
}
sb.append("]");
System.out.println(sb);
}else {
System.out.println(arr);
}
}
}
自定义泛型接口
- 使用了泛型定义的接口就是泛型接口
- 泛型接口的格式:
修饰符 interface 接口名称<泛型变量>{}
- 作用: 泛型接口可以让实现类选择当前功能需要操作的数据类型
- 泛型接口的原理:实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对该类型的操作。
泛型通配符、上下限
通配符:?
-
?
可以在使用泛型的时候代表一切类型 -
E T K V
是在定义泛型的时候使用的
泛型上下限:
-
? extends Car
:?
必须是Car或者其子类 泛型上限 -
? extends Car
:?
必须是Car或者其父类 泛型下限
package com.mochu.d8_genericity_limit;
import java.util.ArrayList;
public class GenericityDemo {
public static void main(String[] args) {
ArrayList<BMW> bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
go(bmws);
ArrayList<BENZ> benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs)
}
public static void go(ArrayList<? extends Car> cars) {
}
}
class Car {
}
class BENZ extends Car {
}
class BMW extends Car {
}
Set系列集合、Collection体系的总结
Set系列集合特点:
- 无序:存储顺序不一致
- 不重复:可以去重复
- 无索引:没有带索引的方法,所以不能使用for循环遍历,也不能通过索引获取元素
Set集合实现类特点:
-
HashSet
:无序、不重复、无索引 -
LinkedHashSet
:有序、不重复、无索引 -
TreeSet
:排序、不重复、无索引
Set集合的功能基本上与Collection的API一致
package com.mochu.d1_Set;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
// 查看Set集合特点:Hashset LinkedHashSet TreeSet
// Set<String> sets = new HashSet<>(); // HashSet特点:无序、不重复、无索引
Set<String> sets = new LinkedHashSet<>(); // LinkedHashSet特点:有序、不重复、无索引
sets.add("Java");
sets.add("Python");
sets.add("PHP");
sets.add("HTML");
sets.add("SpringBoot");
System.out.println(sets);
}
}
HashSet元素无序的底层原理:哈希表
- HashSet集合底层采取哈希表存储的数据
- 哈希表是一种对于增删改查数据性能都比较好的结构
哈希表的组成:
- JDK8之前,底层使用
数组 + 链表
组成 - JDK8之后,底层采用
数组 + 链表 + 红黑树
组成
哈希值:哈希值是JDK根据对象地址,按照某种规则算出来的int类型的数值。
Object类的API:public int hashCode()
:返回对象的哈希值
对象哈希值的特点:
- 同一个对象多次调用
hashCode()
方法返回的哈希值是相同的 - 默认情况下,不同对象的哈希值是不同的
package com.mochu.d1_Set;
public class SetDemo02 {
public static void main(String[] args) {
// 获取对象的哈希值
String name = "mochu7";
String name1 = "slevin";
System.out.println(name.hashCode());
System.out.println(name.hashCode());
System.out.println(name1.hashCode());
System.out.println(name1.hashCode());
}
}
JDK1.8版本开始HashSet原理解析
- 底层结构:哈希表(数组、链表、红黑树的结合体)
- 当挂在元素下面的数据过多时,查询性能降低,从JDK8开始后,当链表长度超过8的时候,自动转换为红黑树
HashSet元素去重复的底层原理
package com.mochu.d2_hashset;
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
Set<Student> sets = new HashSet<>();
// Set集合去重的原因:先判断哈希值再判断equals
Student s1 = new Student("mochu7", 22, "male");
Student s2 = new Student("slevin", 21, "male");
Student s3 = new Student("mochu7", 22, "male");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
sets.add(s1);
sets.add(s2);
sets.add(s3);
// 重写hashcode方法后,s1和s3的哈希值和内容是一样的,会被去重
System.out.println(sets);
}
}
package com.mochu.d2_hashset;
import java.util.Objects;
public class Student {
private String name;
private int age;
private String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name) && Objects.equals(gender, student.gender);
}
@Override
public int hashCode() {
return Objects.hash(name, age, gender);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
实现类:LinkedHashSet
LinkedHashSet
集合概述和特点:有序、不重复、无索引
package com.mochu.d2_hashset;
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<String> sets = new LinkedHashSet<>();
sets.add("Java");
sets.add("Python");
sets.add("PHP");
sets.add("HTML");
System.out.println(sets);
}
}
原理:底层数据结构是依然哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序
实现类:TreeSet
TreeSet
集合概述和特点:
- 不重复、无索引、可排序
- 可排序:按照元素的大小默认升序(有小到大)排序
-
TreeSet
集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好 - 注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序
TreeSet
集合默认的规则
- 对于数值类型:Integer、Double,官方默认按照大小进行升序排序
- 对于字符串类型:默认按照首字符的ASCII编号升序排序
- 对于自定义类型如Student对象,TreeSet无法直接排序(需要制定排序规则)
TreeSet集合存储对象的时候有两种方式可以设计自定义比较规则:
- 方式一:让自定义的类实现Comparable接口重写里面的
compareTo
方法制定比较规则 - 方式二:
TreeSet
集合有参数构造器,可以设置Comparator
接口对应的比较器对象,来定制比较规则
两种方式中,关于返回值的规则:
- 如果认为第一个元素大于第二个元素返回正整数即可
- 如果认为第一个元素小于第二个元素返回负整数即可
- 如果认为第一个元素等于第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两种重复
注意:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序
package com.mochu.d2_hashset;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
Set<Integer> sets = new TreeSet<>(); // 不重复、无索引、可排序
sets.add(23);
sets.add(12);
sets.add(87);
sets.add(67);
sets.add(43);
System.out.println(sets);
System.out.println("---------------------");
Set<String> set1 = new TreeSet<>();
set1.add("Java");
set1.add("Python");
set1.add("末初");
set1.add("PHP");
set1.add("HTML");
set1.add("Slevin");
set1.add("mochu7");
System.out.println(set1);
System.out.println("-------------------");
// 第二种比较方法:集合自带比较器方法
Set<Apple> apples = new TreeSet<>(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
// 降序
// return o2.getWeight() - o1.getWeight();
// 价格比较(降序),浮点型使用Double.compare
return Double.compare(o2.getPrice(), o1.getPrice());
}
});
apples.add(new Apple("红苹果", 10.5, "红色", 500));
apples.add(new Apple("青苹果", 7.5, "青色", 450));
apples.add(new Apple("绿苹果", 8.5, "绿色", 520));
apples.add(new Apple("黄苹果", 12.5, "黄色", 510));
// 指定TreeSet排序规则
System.out.println(apples);
}
}
package com.mochu.d2_hashset;
public class Apple implements Comparable<Apple>{
private String name;
private Double price;
private String color;
private int weight;
public Apple() {
}
public Apple(String name, Double price, String color, int weight) {
this.name = name;
this.price = price;
this.color = color;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", price=" + price +
", color='" + color + '\'' +
", weight=" + weight +
'}';
}
/**
* 第一种比较方式:类自定义比较方法
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较(升序)
return this.weight - o.weight >= 0 ? 1 : -1;
}
}
可变参数、集合操作的工具类Collections
可变参数:
- 可变参数用在形参中可以接受多个数据
- 可变参数的格式:
数据类型...参数名称
可变参数的作用:传输参数非常灵活,方便。可以不传输参数,可以传输1个或者多个,也可以传输一个数组
可变参数在方法内部本质上就是一个数组
可变参数的注意事项:
- 一个形参列表中可变参数只能有一个
- 可变参数必须在形参列表的最后面
package com.mochu.d3_params;
import java.util.Arrays;
public class MethodDemo {
public static void main(String[] args) {
// 不传参
sum();
// 传输一个参数
sum(10);
// 传输多个参数
sum(10, 20, 30);
// 传输数组参数
sum(new int[]{10, 20, 30, 40, 50});
}
public static void sum(int...nums) {
// 注意:可变参数在方法内部就是一个数组
System.out.println("元素个数:" + nums.length);
System.out.println("元素内容:" + Arrays.toString(nums));
}
}
Collections集合工具类
-
java.utils.Collections
是集合工具类 - 作用:
Collections
并不属于集合,是用来操作集合的工具类
package com.mochu.d3_params;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 批量添加元素
Collections.addAll(list, "mochu7", "Slevin", "Shinn", "末初");
System.out.println(list);
// list集合打乱顺序 public static void shuffle(List<?> list)
Collections.shuffle(list);
System.out.println(list);
// list集合排序 public static <T> void sort(List<T> list)
List<Integer> list1 = new ArrayList<>();
Collections.addAll(list1, 12, 54, 67, 23, 63, 97, 56);
Collections.sort(list1);
System.out.println(list1);
}
}
斗地主游戏
package com.mochu.d4_game;
public class Card {
private String size;
private String color;
private int index;
public Card() {
}
public Card(String size, String color, int index) {
this.size = size;
this.color = color;
this.index = index;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return size + color;
}
}
package com.mochu.d4_game;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class GameDemo {
/**
* 定义一个静态集合存储54张牌对象
*/
public static List<Card> allCards = new ArrayList<>();
/**
* 定义静态代码块初始化牌数据
*/
static{
String[] sizes = {"3", "4", "5", "6", "7", "8", "9", "J", "Q", "K", "A", "2"};
String[] colors = {"♦", "♥", "♣", "♠"};
int index = 0; // 牌的权重
for(String size : sizes) {
index++;
for(String color : colors) {
// 封装牌对象
Card c = new Card(size, color, index);
// 存储集合容器
allCards.add(c);
}
}
// 大小王存储牌集合
Card c1 = new Card("", "小王", ++index);
Card c2 = new Card("", "大王", ++index);
Collections.addAll(allCards, c1, c2);
System.out.println("新牌:" + allCards);
}
public static void main(String[] args) {
// 洗牌
Collections.shuffle(allCards);
System.out.println("洗牌后:" + allCards);
// 定义三个玩家,每个玩家定义一个集合容器
List<Card> player1 = new ArrayList<>();
List<Card> player2 = new ArrayList<>();
List<Card> player3 = new ArrayList<>();
// 开始发牌:从牌堆中发出51张牌,剩余三张作为底牌
for (int i = 0; i < allCards.size() - 3; i++) {
Card c = allCards.get(i);
if(i % 3 == 0){
// player1拿牌
player1.add(c);
}else if(i % 3 == 1) {
// player2拿牌
player2.add(c);
}else if(i % 3 == 2) {
// player3拿牌
player3.add(c);
}
}
// 把最后三张牌底牌截取截取到一个子集合
List<Card> lastTreeCard = allCards.subList(allCards.size() - 3, allCards.size());
// 玩家拿到牌之后排序(从大到小)
sortCards(player1);
sortCards(player2);
sortCards(player3);
// 输出玩家的牌
System.out.println("\n");
System.out.println("Player1的牌:" + player1);
System.out.println("Player2的牌:" + player2);
System.out.println("Player3的牌:" + player3);
System.out.println("三张底牌:" + lastTreeCard);
}
/**
* 给玩家的牌做排序(从大到小)
* @param cards
*/
private static void sortCards(List<Card> cards) {
Collections.sort(cards, (o1, o2) -> o2.getIndex() - o1.getIndex());
}
}
Map集合概述、API、遍历方式
Map集合概述
- Map集合是一种双列集合,每个元素包含两个数据
- Map集合的每个元素的格式:
key=value(键值对元素)
- Map集合也被称为”键值对集合“
- Map集合的键:无序、不重复的
Map集合的值:值可以重复
Map集合体系特点
Map集合体系的特点:
- Map集合的特点都是由键决定的
- Map集合的键是无序,不重复的,无索引的,值不做要求(可以重复)
- Map集合后面重复的键对应的值会覆盖前面重复键的值
- Map集合的键值对都可以为null
Map集合实现类特点:
-
HashMap
:元素按照键是无序的,不重复,无索引,值不做要求 -
LinkedHashMap
:元素按照键有序的,不重复,无索引,值不做要求
package com.mochu.d5_map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("iPhone14", 10000);
maps.put("HUAWEI mate50", 6000);
maps.put("JAVA从入门到入土", 50);
maps.put(null, null);
System.out.println(maps);
Map<String, Integer> maps1 = new LinkedHashMap<>();
maps1.put("iPhone14", 10000);
maps1.put("HUAWEI mate50", 6000);
maps1.put("JAVA从入门到入土", 50);
maps1.put(null, null);
System.out.println(maps1);
}
}
Map集合常用的API
package com.mochu.d5_map;
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("iPhone14", 10000);
maps.put("HUAWEI mate50", 6000);
maps.put("JAVA从入门到入土", 50);
maps.put(null, null);
System.out.println(maps);
// 清空集合
// maps.clear();
// 判断集合是否为空
System.out.println(maps.isEmpty());
// 根据键值取值(没有这个键取出来的就是null)
System.out.println(maps.get("iPhone14"));
System.out.println(maps.get("HUAWEI mate50"));
// 根据键值删除
maps.remove("HUAWEI mate50");
System.out.println(maps);
// 判断是否包含某个键值
System.out.println(maps.containsKey("iPhone14"));
// 判断是否包含某个值
System.out.println(maps.containsValue(50));
// 获取全部键集合 public Set<K> keySet()
Set<String> keys = maps.keySet();
System.out.println(keys);
// 获取所有值 Collection<V> values()
Collection<Integer> values = maps.values();
System.out.println(values);
// 集合的大小
System.out.println(maps.size());
// 合并其他map集合
Map<String, Integer> map1 = new HashMap<>();
map1.put("JAVA", 100);
map1.put("Python", 80);
map1.put("C++", 90);
Map<String, Integer> map2 = new HashMap<>();
map2.put("GO", 110);
map2.put("PHP", 70);
map2.put("JavaScript", 120);
map1.putAll(map2);
System.out.println(map1);
}
}
Map集合遍历方式一:键找值
package com.mochu.d5_map;
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("iPhone14", 10000);
maps.put("HUAWEI mate50", 6000);
maps.put("JAVA从入门到入土", 50);
maps.put("xiaomi13", 4500);
System.out.println(maps);
Set<String> keys = maps.keySet();
for(String key : keys) {
int value = maps.get(key);
System.out.println(key + " ==> " + value);
}
}
}
Map遍历集合方式二:键值对
package com.mochu.d5_map;
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("iPhone14", 10000);
maps.put("HUAWEI mate50", 6000);
maps.put("JAVA从入门到入土", 50);
maps.put("xiaomi13", 4500);
System.out.println(maps);
// 把map集合转换成set集合,map集合的元素是键值没有类型,foreach遍历不了,可以通过entrySet()转换成键值对类型然后foreach遍历
Set<Map.Entry<String, Integer>> entries = maps.entrySet();
// 开始遍历
for(Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
int value = entry.getValue();
System.out.println(key + " ==> " + value);
}
}
}
Map集合遍历方式三:Lambda
package com.mochu.d5_map;
import java.util.*;
import java.util.function.BiConsumer;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("iPhone14", 10000);
maps.put("HUAWEI mate50", 6000);
maps.put("JAVA从入门到入土", 50);
maps.put("xiaomi13", 4500);
System.out.println(maps);
maps.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String key, Integer value) {
System.out.println(key + " ==> " + value);
}
});
// 简化
maps.forEach((key, value) -> {
System.out.println(key + " ==> " + value);
});
}
}
Map集合案例、其他实现类
package com.mochu.d6_map_test;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class MapTest1 {
public static void main(String[] args) {
String[] selects = {"A", "B", "C", "D"};
StringBuilder sb = new StringBuilder();
Random rd = new Random();
for (int i = 0; i < 80; i++) {
sb.append(selects[rd.nextInt(selects.length)]);
}
System.out.println(sb);
// 统计结果,封装成键值对
Map<Character, Integer> infos = new HashMap<>();
// 遍历80个学生选择数据
for (int i = 0; i < sb.length(); i++) {
// 提取当前选择的经典字符
char ch = sb.charAt(i);
// 判断Map集合中是否存在这个值
if(infos.containsKey(ch)) {
infos.put(ch, infos.get(ch) + 1);
}else {
// 第一次选择该经典
infos.put(ch, 1);
}
}
System.out.println(infos);
}
}
Map集合的实现类LinkedHashMap
Map集合的实现类:TreeMap
集合嵌套
package com.mochu.d6_map_test;
import java.util.*;
public class MapTest1 {
public static void main(String[] args) {
// 记录每个学生选择的情况,使用Map集合
Map<String, List<String>> data = new HashMap<>();
List<String> selects = new ArrayList<>();
Collections.addAll(selects, "A", "C");
data.put("甲", selects);
List<String> selects1 = new ArrayList<>();
Collections.addAll(selects1, "B", "C", "D");
data.put("乙", selects1);
List<String> selects2 = new ArrayList<>();
Collections.addAll(selects2, "A", "B", "C", "D");
data.put("丙", selects2);
System.out.println(data);
// 统计每个景点选择的人数
Map<String, Integer> infos = new HashMap<>();
Collection<List<String>> values = data.values();
for (List<String> value : values) {
for (String s : value) {
// 判断是否包含景点
if(infos.containsKey(s)) {
infos.put(s, infos.get(s) + 1);
}else {
infos.put(s, 1);
}
}
}
System.out.println(infos);
}
}
创建不可变集合
什么是不可变集合?
- 不可变集合,就是不可被修改的集合
- 集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变,否则报错
package com.mochu.d1_unchange_collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class CollectionDemo {
public static void main(String[] args) {
// 不可变list集合
List<Integer> lists = List.of(10, 20, 30, 40, 50);
// lists.add(11); // 不能添加,否则报错
// lists.set(2, 22); // 不能修改,否则报错
System.out.println(lists.get(1));
// 不可变set集合
Set<String> names = Set.of("Mochu7", "Slevin", "Shinn");
// names.add("test");
System.out.println(names);
// 不可变的map集合
Map<String, Integer> maps = Map.of("iPhone14", 10000, "HUAWEI mate50", 5000);
// maps.put("JAVA从入门到入土", 50);
System.out.println(maps);
}
}
Stream流体系
什么是Stream流?
- 在Java8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念
- 目的:用于简化集合和数组操作的API
package com.mochu.d2_stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class StreamTest {
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 : names) {
if(name.length() == 3) {
zhangThreeList.add(name);
}
}
System.out.println(zhangThreeList);
// 使用Stream实现
names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
}
}
Stream流的获取
Stream流的三类方法:
- 获取Stream流
– 创建一条流水线,并把数据放到流水线上准备进行操作 - 中间方法
– 流水线上操作。一次操作完毕之后,还可以继续进行其他操作 - 终结方法
– 一个Stream流只能由一个终结方法,是流水线上的最后一个操作
package com.mochu.d2_stream;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
// Collection获取Stream流
Collection<String> list = new ArrayList<>();
Stream<String> s = 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>> keyAndValueStream = map.entrySet().stream(); // 键值对流
// 数组获取流
String[] names = {"mochu7", "slevin", "shinn"};
Stream<String> nameStream = Arrays.stream(names);
Stream<String> nameStream2 = Stream.of(names);
}
}
Stream流常用的API
package com.mochu.d2_stream;
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 StreamDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "mochu7", "Slevin", "Shinn", "末初");
// list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// return s.startsWith("S");
// }
// });
// 简化
list.stream().filter(s -> s.startsWith("S")).forEach(s -> System.out.println(s));
long size = list.stream().filter(s -> s.length() == 5).count();
System.out.println(size);
list.stream().filter(s -> s.startsWith("S")).limit(2).forEach(s -> System.out.println(s));
list.stream().filter(s -> s.startsWith("S")).limit(2).forEach(System.out::println);
list.stream().filter(s -> s.startsWith("S")).skip(2).forEach(System.out::println);
// Map加工方法,在每个元素前加个前缀
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return "名称:" + s;
}
});
list.stream().map(s -> "名称:" + s).forEach(s -> System.out.printf(s));
// 把所有名称加工成一个学生对象
list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));
// list.stream().map(Student::new).forEach(System.out::println); // 构造器引用 方法引用
// 合并流
Stream<String> s1 = list.stream().filter(s -> s.startsWith("S"));
Stream<String> s2 = Stream.of("Java", "Python");
Stream<String> s3 = Stream.concat(s1, s2);
}
}
终结方法和非终结方法的含义:终结方法后流不可以继续使用,非终结方法会返回新的流,支持链式编程
Stream流的综合应用
package com.mochu.d3_stream_app;
public class Employee {
private String name;
private char sex;
private double salary;
private double bouns;
private String punish;
public Employee() {
}
public Employee(String name, char sex, double salary, double bouns, String punish) {
this.name = name;
this.sex = sex;
this.salary = salary;
this.bouns = bouns;
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 getBouns() {
return bouns;
}
public void setBouns(double bouns) {
this.bouns = bouns;
}
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 +
", bouns=" + bouns +
", punish='" + punish + '\'' +
'}';
}
}
package com.mochu.d3_stream_app;
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 +
'}';
}
}
package com.mochu.d3_stream_app;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamApp {
public static double allMoney;
public static double allMoney2; // 两个部门薪资总和
public static void main(String[] args) {
List<Employee> department1 = new ArrayList<>();
department1.add(new Employee("希尔伯特·让·昂热", '男', 5000000, 1000000, "不听董事会命令"));
department1.add(new Employee("莱昂纳多·弗拉梅尔", '男', 1000000, 500000, null));
department1.add(new Employee("古德里安", '男', 500000, 200000, null));
department1.add(new Employee("格尔德·鲁道夫·曼施坦因", '男', 200000, 100000, null));
List<Employee> department2 = new ArrayList<>();
department2.add(new Employee("路明非", '男', 1000000, 2000000, null));
department2.add(new Employee("楚子航", '男', 80000, 100000, "血统存在龙化风险"));
department2.add(new Employee("芬格尔", '男', 100000, 200000, null));
department2.add(new Employee("凯撒·加图索", '男', 100000, 200000, "不听家族安排"));
// 一部的员工最高工资
// Employee e = department1.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBouns(), e1.getSalary()+ e2.getBouns())).get();
// System.out.println(e);
TopperFormer top = department1.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBouns(), e1.getSalary()+ e2.getBouns()))
.map(e -> new TopperFormer(e.getName(), e.getSalary() + e.getBouns())).get();
System.out.println(top);
// 统计年均工资(去掉最高和最低工资)
department1.stream().sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBouns(), e1.getSalary()+ e2.getBouns())).
skip(1).limit(department1.size() - 2).forEach(e -> {
// 求剩余员工薪资总和
allMoney += (e.getSalary() + e.getBouns());
});
System.out.println("Department1的平均薪资:" + allMoney / (department1.size() - 2));
// 合并两个集合流,再统计
Stream<Employee> s1 = department1.stream();
Stream<Employee> s2 = department2.stream();
Stream<Employee> s3 = Stream.concat(s1, s2);
s3.sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBouns(), e1.getSalary()+ e2.getBouns())).
skip(1).limit(department1.size() + department2.size() - 2).forEach(e -> {
// 求剩余员工薪资总和
allMoney2 += (e.getSalary() + e.getBouns());
});
BigDecimal a = BigDecimal.valueOf(allMoney2);
BigDecimal b = BigDecimal.valueOf(department1.size() + department2.size() - 2);
System.out.println("两个部门的平均薪资:" + a.divide(b, 2, RoundingMode.HALF_UP));
}
}
收集Stream流
Stream流的收集操作
- 收集Stream流的含义:就是把Stream流操作后的结果数据转会到集合或者数组中去
- Stream流:方便操作集合/数组的手段
- 集合/数组:才是开发中的目的
package com.mochu.d3_stream_app;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 收集Stream流到集合或者数组中
*/
public class StreamDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "Mochu7", "Slevin", "Shinn");
// 收集到list中
Stream<String> s1 = list.stream().filter(s -> s.startsWith("S"));
List<String> list1 = s1.collect(Collectors.toList());
System.out.println(list1);
// 收集到set中
// 注意:流只能使用一次,使用完之后会关闭
Stream<String> s2 = list.stream().filter(s -> s.startsWith("S"));
Set<String> set = s2.collect(Collectors.toSet());
System.out.println(set);
// 收集到数组
Stream<String> s3 = list.stream().filter(s -> s.startsWith("S"));
Object[] arr = s3.toArray();
System.out.println(Arrays.toString(arr));
}
}
异常概述、体系
什么是异常?
- 异常是程序在“编译”或者“执行”的过程中可能会出现的问题
- 注意:语法错误不算在异常体系中
- 异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止
常见运行时异常
异常的处理机制
编译时异常的处理机制
异常的强大演示、自定义异常
package com.mochu.d4_exception;
import java.util.Scanner;
public class ExceptionDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
try {
System.out.println("请输入合法的价格:");
String priceStr = sc.nextLine();
// 转换成Double类型的价格
double price = Double.valueOf(priceStr);
// 判断价格是否大于0
if(price > 0) {
System.out.println("定价:" + price);
break;
}else {
System.out.println("价格必须为正数");
}
} catch (Exception e) {
System.out.println("用户输入的数据有误,请重新输入");
}
}
}
}
自定义异常
1、自定义编译时异常
- 定义一个异常类继承
Exception
- 重写构造器
- 在出现异常的地方用
throw new
自定义对象抛出
package com.mochu.d4_exception;
public class AgeIlleagalException extends Exception{
public AgeIlleagalException() {
}
public AgeIlleagalException(String message) {
super(message);
}
}
2、自定义运行时异常
- 定义一个异常类继承
RuntimeException
- 重写构造器
- 在出现异常的地方用
throw new
自定义对象抛出
package com.mochu.d4_exception;
public class AgeIlleagalRuntimeException extends RuntimeException{
public AgeIlleagalRuntimeException() {
}
public AgeIlleagalRuntimeException(String message) {
super(message);
}
}
package com.mochu.d4_exception;
public class ExceptionDemo {
public static void main(String[] args) {
// 需求:年龄小于0或者大于200就是异常
}
public static void checkAge(int age) throws AgeIlleagalException{
if(age < 0 || age > 200) {
// 抛出异常对象给调用者
// throw:在方法内部直接创建一个异常对象,并从此点抛出
// throws:用在方法声明上的,抛出方法内部的异常
throw new AgeIlleagalException(age + "瞎搞");
// throw new AgeIlleagalRuntimeException(age + "瞎搞");
}else {
System.out.println("年龄合法");
}
}
}
日志概述、日志技术体系
Logback日志框架:
- logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好
- 官方网站:https://logback.qos.ch/index.html
- Logback是基于slf4j的日志规范实现的框架
Logback主要分为三个技术模块:
-
logback-core
:logback-core模块为其他两个模块奠定了基础,必须有 -
logback-classic
:它是log4j的一个改良版本,同时它完整的实现了slf4j API
-
logback-access
:模块与Tomcat和Jetty等Servlet容器集成,以提供HTTP访问日志功能
Logback日志框架的快速入门、日志级别设置等
首先需要导入Logback日志技术到项目中,用于记录系统的日志信息
- 在项目下新建文件夹
lib
,导入Logback的相关jar包到该文件夹下,并添加到项目依赖库中去。
然后全部选中,右键Add as Library
- 将Logback的核心配置文件
logback.xml
直接拷贝到src
目录下logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="D:/Java/log" />
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志输出编码 -->
<Encoding>UTF-8</Encoding>
<layout class="ch.qos.logback.classic.PatternLayout">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
</pattern>
</layout>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8</Encoding>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/myApp.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
</pattern>
</layout>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>1MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="ALL">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>
- 在代码中获取日志对象
public static final Logger LOGGER = LoggerFactory.getLogger("类对象");
package com.mochu.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 快速搭建Logback日志框架,记录程序执行情况到文件中
*/
public class Test {
// 创建Logback的日志对象
public static final Logger LOGGER = LoggerFactory.getLogger("Test.class");
public static void main(String[] args) {
try {
LOGGER.debug("main方法开始执行");
LOGGER.info("我开始记录第二行日志");
int a = 10;
int b = 0;
LOGGER.trace("a=" + a);
LOGGER.trace("b=" + b);
System.out.println(a / b);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("功能出现异常" + e);
}
}
}
Logback配置详解-输出位置、格式位置
Logback日志输出位置、格式设置
- 通过
logback.xml
中的<append>
标签可以设置输出位置和日志信息的详细格式 - 通常可以设置2个日志输出位置:一个是控制台、一个是系统文件
输出到控制台的配置:<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
输出到系统文件的配置:<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
Logback配置详解-日志级别设置
日志级别:
- 级别程度依次是:
TRACE < DEBUG < INFO < WARN < ERROR
;默认级别是debug(忽略大小写),对应其方法 - 作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息
-
ALL
和OFF
分别是打开全部日志信息,以及关闭全部日志信息
<!-- 日志输出级别 -->
<root level="ALL">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
影院系统开发
日志框架搭建、系统角色分析、容器定义
首页、登录、商家界面、用户界面实现
商家功能:展示详情、影片上架、退出
影片下架、修改、展示排片信息、用户购票
用户功能-展示全部影片
用户功能-购票操作
package com.mochu.bean;
public class Business extends User{
private String shopName; // 店铺名称
private String address; // 店铺地址
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package com.mochu.bean;
/**
* 客户类
*/
public class Customer extends User{
}
package com.mochu.bean;
import java.util.Date;
public class Movie {
private String name;
private String actor;
private double score;
private double time;
private double price;
private int number; // 余票
private Date startTime; // 上映时间
public Movie() {
}
public Movie(String name, String actor, double time, double price, int number, Date startTime) {
this.name = name;
this.actor = actor;
this.score = score;
this.time = time;
this.price = price;
this.number = number;
this.startTime = startTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public double getTime() {
return time;
}
public void setTime(double time) {
this.time = time;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
}
package com.mochu.bean;
/**
* 用户类(客户和商家的父类)
*/
public class User {
private String loginName;
private String userName;
private String passWord;
private char sex;
private String phone;
private double money;
public User() {
}
public User(String loginName, String userName, String passWord, char sex, String phone, double money) {
this.loginName = loginName;
this.userName = userName;
this.passWord = passWord;
this.sex = sex;
this.phone = phone;
this.money = money;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
package com.mochu.run;
import com.mochu.bean.Business;
import com.mochu.bean.Customer;
import com.mochu.bean.Movie;
import com.mochu.bean.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class MovieSystem {
// 存储用户数据的容器
public static final List<User> ALL_USERS = new ArrayList<>();
// 商家信息容器
public static final Map<Business, List<Movie>> ALL_MOVIES = new HashMap<>();
// 扫描器对象
public static final Scanner SYS_SC = new Scanner(System.in);
// 静态的用户变量,记录当前登陆成功的对象
public static User loginUser;
public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
public static final Logger LOGGER= LoggerFactory.getLogger("MovieSystem.class");
// 利用静态代码块加载一些测试数据
static {
Customer c = new Customer();
c.setLoginName("mochu7");
c.setPassWord("mochu777");
c.setUserName("末初");
c.setSex('男');
c.setMoney(10000);
c.setPhone("18888888888");
ALL_USERS.add(c);
Customer c1 = new Customer();
c1.setLoginName("Slevin");
c1.setPassWord("123456");
c1.setUserName("斯莱文");
c1.setSex('男');
c1.setMoney(100000);
c1.setPhone("17777777777");
ALL_USERS.add(c1);
Business b = new Business();
b.setLoginName("Shinn");
b.setPassWord("Shinn888");
b.setUserName("楚末");
b.setMoney(0);
b.setSex('男');
b.setPhone("16666666666");
b.setAddress("银河太阳系地球星光大道1号");
b.setShopName("星河国际影城");
ALL_USERS.add(b);
List<Movie> movies = new ArrayList<>();
ALL_MOVIES.put(b, movies);
Business b1 = new Business();
b1.setLoginName("movoc");
b1.setPassWord("movoc777");
b1.setUserName("莫莫扣");
b1.setMoney(0);
b1.setSex('女');
b1.setPhone("15555555555");
b1.setAddress("银河太阳系地球银河大道8号");
b1.setShopName("银河国际影城");
ALL_USERS.add(b1);
List<Movie> movies1 = new ArrayList<>();
ALL_MOVIES.put(b1, movies1);
}
public static void main(String[] args) {
showMain();
}
/**
* 首页展示
*/
private static void showMain() {
while (true) {
System.out.println("=======================电影首页=======================");
System.out.println("1、登录:");
System.out.println("2、用户注册:");
System.out.println("3、商家注册:");
System.out.println("请输入操作命令:");
String command = SYS_SC.nextLine();
switch(command) {
case "1":
login();
break;
case "2":
break;
case "3":
break;
default:
System.out.println("命令有误,请重新确认");
}
}
}
/**
* 登录功能
*/
private static void login() {
while (true) {
System.out.println("请输入登录名称:");
String loginName = SYS_SC.nextLine();
System.out.println("请输入用户密码:");
String passWord = SYS_SC.nextLine();
User u = getUserByLoginName(loginName);
if(u != null) {
// 登录名核验成功
if(u.getPassWord().equals(passWord)) {
// 登录成功,判断用户还是商家
loginUser = u;
LOGGER.info(u.getUserName() + "登录系统");
if(u instanceof Customer) {
// 普通用户
showCustomerMain();
}else {
// 商家
showBusinessMain();
}
// 结束login
return;
}else {
System.out.println("密码错误");
}
}else {
System.out.println("登录名称错误");
}
}
}
/**
* 商家页面
*/
private static void showBusinessMain() {
while(true) {
System.out.println("=======================商家页面=======================");
System.out.println(loginUser.getUserName() + (loginUser.getSex() == '男' ? "先生" : "女士") + "欢迎您~");
System.out.println("1. 展示详情:");
System.out.println("2. 上架电影:");
System.out.println("3. 下架电影:");
System.out.println("4. 修改电影:");
System.out.println("5. 退出系统:");
System.out.println("请输入你要操作的命令:");
String command = SYS_SC.nextLine();
switch(command) {
case "1":
// 展示商家详细信息
showBusinessInfos();
break;
case "2":
// 上架电影
addMovie();
break;
case "3":
// 下架电影
deleteMovie();
break;
case "4":
// 修改电影
updateMovie();
break;
case "5":
System.out.println(loginUser.getUserName() + (loginUser.getSex() == '男' ? "先生" : "女士") + "感谢您的使用~");
// 退出系统
return;
default:
System.out.println("命令有误,请重新输入");
}
}
}
/**
* 修改影片
*/
private static void updateMovie() {
System.out.println("=======================修改电影=======================");
Business business = (Business) loginUser;
List<Movie> movies = ALL_MOVIES.get(business);
if(movies.size() == 0) {
System.out.println("当前没有影片可以修改");
return;
}
while (true) {
System.out.println("请输入需要修改的电影名称:");
String movieName = SYS_SC.nextLine();
// 根据电影名称查询是否有这个电影对象
Movie movie = getMovieByName(movieName);
if(movie != null) {
System.out.println("请输入修改后的电影名称:");
String name = SYS_SC.nextLine();
System.out.println("请输入修改后的电影主演:");
String actor = SYS_SC.nextLine();
System.out.println("请输入修改后的电影时长:");
String time = SYS_SC.nextLine();
System.out.println("请输入修改后的电影票价:");
String price = SYS_SC.nextLine();
System.out.println("请输入修改后的电影票数:");
String totalNumber = SYS_SC.nextLine();
while (true) {
try {
System.out.println("请输入修改后的电影放映时间:");
String startTime = SYS_SC.nextLine();
movie.setName(name);
movie.setActor(actor);
movie.setTime(Double.valueOf(time));
movie.setPrice(Double.valueOf(price));
movie.setNumber(Integer.valueOf(totalNumber));
movie.setStartTime(sdf.parse(startTime));
System.out.println("电影修改成功");
showBusinessInfos();
return;
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("时间解析出错");
}
}
}else {
System.out.println("您的店铺没有上架该影片");
System.out.println("是否继续下架?y/n");
String command = SYS_SC.nextLine();
switch(command) {
case "y":
break;
default:
System.out.println("ok");
return;
}
}
}
}
/**
* 影片下架
*/
private static void deleteMovie() {
System.out.println("=======================下架电影=======================");
Business business = (Business) loginUser;
List<Movie> movies = ALL_MOVIES.get(business);
if(movies.size() == 0) {
System.out.println("当前没有影片可以下架");
return;
}
while (true) {
System.out.println("请输入需要下架的电影名称:");
String movieName = SYS_SC.nextLine();
// 根据电影名称查询是否有这个电影对象
Movie movie = getMovieByName(movieName);
if(movie != null) {
movies.remove(movie);
System.out.println("您的店铺已经成功下架了:" + movie.getName());
showBusinessInfos();
return;
}else {
System.out.println("您的店铺没有上架该影片");
System.out.println("是否继续下架?y/n");
String command = SYS_SC.nextLine();
switch(command) {
case "y":
break;
default:
System.out.println("ok");
return;
}
}
}
}
/**
* 根据名称查询影片对象
* @param movieName
* @return
*/
public static Movie getMovieByName(String movieName) {
Business business = (Business) loginUser;
List<Movie> movies = ALL_MOVIES.get(business);
for(Movie movie : movies) {
if(movie.getName().contains(movieName)) {
return movie;
}
}
return null;
}
/**
* 商家电影添加
*/
private static void addMovie() {
System.out.println("=======================商家电影=======================");
Business business = (Business) loginUser;
List<Movie> movies = ALL_MOVIES.get(loginUser);
System.out.println("请输入电影名称:");
String name = SYS_SC.nextLine();
System.out.println("请输入电影主演:");
String actor = SYS_SC.nextLine();
System.out.println("请输入电影时长:");
String time = SYS_SC.nextLine();
System.out.println("请输入电影票价:");
String price = SYS_SC.nextLine();
System.out.println("请输入电影票数:");
String totalNumber = SYS_SC.nextLine();
while (true) {
try {
System.out.println("请输入电影放映时间:");
String startTime = SYS_SC.nextLine();
// Movie(String name, String actor, double time, double price, int number, Date startTime)
Movie movie = new Movie(name, actor, Double.valueOf(time), Double.valueOf(price), Integer.valueOf(totalNumber), sdf.parse(startTime));
movies.add(movie);
System.out.println("电影上架成功");
return;
} catch (ParseException e) {
e.printStackTrace();
LOGGER.error("时间解析出错");
}
}
}
/**
* 展示商家信息
*/
private static void showBusinessInfos() {
System.out.println("=======================商家详情=======================");
LOGGER.info(loginUser.getUserName() + "商家展示详情");
// 根据商家对象作为Map集合的键,提取对应的影片信息:Map<Busines, List<Movie>>
// loginUser就是当前登录用户
Business business = (Business) loginUser;
System.out.println("店铺:" + business.getShopName() + "\t\t电话:" + business.getPhone() + "\t\t地址:" + business.getAddress() + "\t\t余额:" + business.getMoney());
List<Movie> movies = ALL_MOVIES.get(loginUser);
System.out.println("片名\t\t\t主演\t\t时长\t\t评分\t\t票价\t\t余票数量\t\t上映时间");
if (movies.size() > 0) {
for(Movie movie : movies) {
System.out.println(movie.getName() + "\t\t\t" + movie.getActor() + "\t\t" + movie.getTime() + "\t\t" + movie.getScore() +
"\t\t" + movie.getPrice() + "\t\t" + movie.getNumber() + "\t\t" + sdf.format(movie.getStartTime()));
}
}else {
System.out.println("您的店铺当前没有电影上架");
}
}
/**
* 客户页面
*/
private static void showCustomerMain() {
while(true) {
System.out.println("=======================客户页面=======================");
System.out.println(loginUser.getUserName() + (loginUser.getSex() == '男' ? "先生" : "女士") + "欢迎您~" + "\t\t余额:" + loginUser.getMoney());
System.out.println("1. 展示全部影片信息功能:");
System.out.println("2. 根据电影名称查询电影信息:");
System.out.println("3. 评分功能:");
System.out.println("4. 购票功能:");
System.out.println("5. 退出系统:");
System.out.println("请输入你要操作的命令:");
String command = SYS_SC.nextLine();
switch(command) {
case "1":
// 展示全部影片信息
showAllMovies();
break;
case "2":
// 根据影片名查询信息
break;
case "3":
// 评分
break;
case "4":
// 购票
buyMovie();
break;
case "5":
// 退出系统
// 结束showCustomerMain
return;
default:
System.out.println("命令有误,请重新输入");
}
}
}
/**
* 用户购票功能
*/
private static void buyMovie() {
showAllMovies();
System.out.println("=======================用户购票=======================");
while (true) {
System.out.println("请您输入需要买票的门店:");
String shopName = SYS_SC.nextLine();
// 查询是否存在该商家
Business business = getBusinessByShopName(shopName);
if(business == null) {
System.out.println("对不起,没有该店铺");
}else {
// 商家全部排片
List<Movie> movies = ALL_MOVIES.get(business);
// 判断是否存在上映的电影
if(movies.size() > 0) {
// 选片
while (true) {
System.out.println("请输入需要购买电影的名称:");
String movieName = SYS_SC.nextLine();
// 在当前商家下,查询电影
Movie movie = getMovieByShopAndName(business, movieName);
if(movie != null) {
// 开始购买
while (true) {
System.out.println("请您输入要购买的电影票数:");
String number = SYS_SC.nextLine();
int buyNumber = Integer.valueOf(number);
// 判断电影是否购票
if(movie.getNumber() >= buyNumber) {
double money = BigDecimal.valueOf(movie.getPrice()).multiply(BigDecimal.valueOf(buyNumber)).doubleValue();
if(loginUser.getMoney() >= money) {
// 钱够了,可以买票了
System.out.println("您成功购买了" + movie.getName() + "的影票 " + buyNumber + "张,总金额是:" + money);
// 更新自己和商家金额
loginUser.setMoney(loginUser.getMoney() - money);
business.setMoney(business.getMoney() + money);
movie.setNumber(movie.getNumber() - buyNumber);
return;
}else {
// 钱不够
System.out.println("是否继续买票?y/n");
String command = SYS_SC.nextLine();
switch(command) {
case "y":
break;
default:
System.out.println("感谢光临" + shopName);
return;
}
}
}else {
System.out.println("您当前最多可以购买:" + movie.getNumber());
System.out.println("是否继续买票?y/n");
String command = SYS_SC.nextLine();
switch(command) {
case "y":
break;
default:
System.out.println("感谢光临" + shopName);
return;
}
}
}
}else {
System.out.println("您输入的电影名称有误");
}
}
}else {
System.out.println("该影院暂时没有上架的影片");
System.out.println("是否继续买票?y/n");
String command = SYS_SC.nextLine();
switch(command) {
case "y":
break;
default:
System.out.println("感谢光临" + shopName);
return;
}
}
}
}
}
/**
* 根据商家查询电影是否存在
* @param business
* @param name
* @return
*/
public static Movie getMovieByShopAndName(Business business, String name) {
List<Movie> movies = ALL_MOVIES.get(business);
for (Movie movie : movies) {
if(movie.getName().contains(name)) {
return movie;
}
}
return null;
}
/**
* 根据店铺名称查询商家对象
* @return
*/
public static Business getBusinessByShopName(String shopName){
Set<Business> businesses = ALL_MOVIES.keySet();
for (Business business : businesses) {
if(business.getShopName().equals(shopName)) {
return business;
}
}
return null;
}
/**
* 展示所有商家排片信息
*/
private static void showAllMovies() {
System.out.println("=======================商家排片=======================");
ALL_MOVIES.forEach(((business, movies) -> {
System.out.println("店铺:" + business.getShopName() + "\t\t电话:" + business.getPhone() + "\t\t地址:" + business.getAddress());
System.out.println("片名\t\t\t主演\t\t时长\t\t评分\t\t票价\t\t余票数量\t\t上映时间");
for(Movie movie : movies) {
System.out.println(movie.getName() + "\t\t\t" + movie.getActor() + "\t\t" + movie.getTime() + "\t\t" + movie.getScore() +
"\t\t" + movie.getPrice() + "\t\t" + movie.getNumber() + "\t\t" + sdf.format(movie.getStartTime()));
}
}));
return;
}
public static User getUserByLoginName(String loginName) {
for (User user : ALL_USERS) {
if(user.getLoginName().equals(loginName)) {
return user;
}
}
return null;
}
}