日期类&异常类
作业:千位数字相乘
public static void main(String[] args) {// 两个千位数字相乘int[] arr1 = {7,8,9,9,8,9};int[] arr2 = {7,9,8,9,6,8};// 定义结果的数组int[] result = new int[12];for (int i = 0; i < arr1.length; i++) {for (int j = 0; j < arr2.length; j++) {result[i + j] += arr1[i] * arr2[j];}}// 统一处理进位问题for (int i = 0; i < result.length - 1; i++) {int temp = result[i];result[i] = temp % 10;result[i + 1] += (temp / 10);}System.out.println(Arrays.toString(result));}
1 日期类
1.1 Date类
public static void main(String[] args) throws ParseException {// 获取当前时间Date date = new Date();// 设置计算机元年之后的时间date.setTime(10000L);System.out.println(date);// 获取计算机元年到现在的毫秒值System.out.println(date.getTime());// 计算机元年在中国是 1970年1月1日早上8点// 从计算机元年开始加上传入的毫秒值的时间Date date1 = new Date(1718937063489L);System.out.println(date1);// 日期格式化SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");// 把日期转换成字符串
// String str = simpleDateFormat.format(new Date());
// System.out.println(str);String str = "2035年10月1日 12:12:12";// 把字符串转日期Date date2 = simpleDateFormat.parse(str);System.out.println(date2);}
1.2 Calendar类
public static void main(String[] args) throws ParseException {// 日历类 获取默认时区的日历Calendar calendar = Calendar.getInstance();// 设置指定的字段
// calendar.set(Calendar.YEAR,2050);
// calendar.set(2050,9,1,12,0,0);String str = "2050-10-1 12:12:12";// 把字符串转换成日期SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = simpleDateFormat.parse(str);// 设置时间calendar.setTime(date);System.out.println(calendar);// 获取日历的相关信息// 年int year = calendar.get(Calendar.YEAR);System.out.println(year);// 月 从0开始 需要加1int month = calendar.get(Calendar.MONTH);System.out.println(month + 1);// 日int day = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(day);// 小时int hour = calendar.get(Calendar.HOUR);System.out.println(hour);// 分int minute = calendar.get(Calendar.MINUTE);System.out.println(minute);// 秒int second = calendar.get(Calendar.SECOND);System.out.println(second);// 毫秒int milliSecond = calendar.get(Calendar.MILLISECOND);System.out.println(milliSecond);// 一年的第几天int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);System.out.println(dayOfYear);// 一个月的第几周int weekOfMonth = calendar.get(Calendar.WEEK_OF_MONTH);System.out.println(weekOfMonth);}
课堂练习:假设每个月的第三周的周五股市开放交易。其他时间无法交易。输入一个时间,判断这个时间是否允许交易并且提示:
交易未开始,交易已结束,交易正在进行中
public static void method() throws ParseException {
// 假设每个月的第三周的周五股市开放交易。其他时间无法交易。
// 输入一个时间,判断这个时间是否允许交易并且提示:
// 交易未开始,交易已结束,交易正在进行中System.out.println("请输入您想查询的日期");Scanner scanner = new Scanner(System.in);// 2018-01-01String str = scanner.next();// 把字符串转换成日期SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date date = simpleDateFormat.parse(str);// 获取日历类Calendar calendar = Calendar.getInstance();// 给日历设置时间calendar.setTime(date);// 获取第几周int week = calendar.get(Calendar.WEEK_OF_MONTH);// 获取日int day = calendar.get(Calendar.DAY_OF_WEEK);// 判断交易状态if (week == 3 && day == 6){System.out.println("交易正在进行中");}else if (week < 3 || week == 3 && day < 6){System.out.println("交易未开始");}else {System.out.println("交易已结束");}}
1.3 time包
jdk1.8之后,对时间体系进行了新的划分,将日期和时间以及其他信息进行分割,从而分出来一个代表时间的包---java.time
1.3.1 LocalDate类
只有日期(年月日),没有时间(时分秒)
public static void main(String[] args) {// 获取当前时间LocalDate date = LocalDate.now();System.out.println(date);// 指定日期LocalDate date1 = LocalDate.of(2014, 6, 5);System.out.println(date1);// 添加天数
// date = date.plusDays(3);// 添加月数
// date = date.plusMonths(3);// 添加周的天数
// date = date.plusWeeks(1);// 添加年数
// date = date.plusYears(3);date = date.plus(3, ChronoUnit.DAYS);System.out.println(date);// LocalDate和String的相互转换// 日期时间格式转换器DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");// 将日期转换成字符串String str = dateTimeFormatter.format(date);System.out.println(str);// 将字符串转换成日期LocalDate date2 = LocalDate.parse(str, dateTimeFormatter);System.out.println(date2);}
1.3.2 LocalTime类
只有时间,没有日期。精确到纳秒
private static void demo2() {// 获取当前时间LocalTime time = LocalTime.now();System.out.println(time);// 指定时间
// LocalTime time1 = LocalTime.of(18, 0, 1);
// System.out.println(time1);// 添加时间// 添加小时time = time.plusHours(3);// 添加分钟
// time.plusMinutes()// 添加秒
// time.plusSeconds();// 添加纳秒
// time.plusNanos();time = time.plus(3,ChronoUnit.HOURS);System.out.println(time);// 减少time = time.minus(4,ChronoUnit.HOURS);// 减少小时
// time.minusHours();// 减少分钟
// time.minusMinutes()// 减少秒
// time.minusSeconds()// 减少纳秒
// time.minusNanos();System.out.println(time);// LocalDate和String的相互转换// 日期时间格式转换器DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH-mm-ss-SSS");// 将日期转换成字符串String str = dateTimeFormatter.format(time);System.out.println(str);// 将字符串转换成日期LocalTime date2 = LocalTime.parse(str, dateTimeFormatter);System.out.println(date2);}
1.3.3 LocalDateTime类
有日期有时间,精确到纳秒
private static void demo3() {// 获取时间LocalDateTime localDateTime = LocalDateTime.now();System.out.println(localDateTime);// 指定时间LocalDateTime dateTime = LocalDateTime.of(2027, 12, 12, 5, 6, 7);System.out.println(dateTime);// 添加时间dateTime = dateTime.plus(3,ChronoUnit.CENTURIES);System.out.println(dateTime);// 减少时间dateTime = dateTime.minus(3,ChronoUnit.HOURS);System.out.println(dateTime);DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss:SSS");// 把日期转换成字符串String str = formatter.format(dateTime);System.out.println(str);// 把字符串转换成日期LocalDateTime parse = LocalDateTime.parse(str, formatter);System.out.println(parse);}
1.3.4 Instant
private static void demo4() {// 当前北京时间距离世界时间相差8小时// 获取当前的北京时间Instant now1 = Instant.now(Clock.offset(Clock.systemUTC(), Duration.ofHours(8)));System.out.println(now1);// 获取当前世界时间Instant now = Instant.now();System.out.println(now);// 添加时间
// now = now.plus(8,ChronoUnit.HOURS);
// System.out.println(now);// 比较两个时间的差值long duration = now.until(Instant.now(), ChronoUnit.HOURS);System.out.println(duration);// 获取毫秒System.out.println(now.get(ChronoField.MILLI_OF_SECOND));// 获取微秒System.out.println(now.get(ChronoField.MICRO_OF_SECOND));// 获取纳秒System.out.println(now.get(ChronoField.NANO_OF_SECOND));// 将Instant转换成LocalDateTime类型// ZoneId.systemDefault() 默认时区LocalDateTime localDateTime = LocalDateTime.ofInstant(now, ZoneId.systemDefault());System.out.println(localDateTime);}
1.3.5 间隔相关的日期类
- Period 用于计算两个日期间隔
LocalDate d1 = LocalDate.now();LocalDate d2 = LocalDate.of(2022, 12, 12);Period between = Period.between(d2, d1);System.out.println("相差的年数" + Math.abs(between.getYears()));System.out.println("相差的月数" + between.getMonths());System.out.println("相差的天数" + between.getDays());
- Duration:用于计算两个时间间隔
private static void demo6() {LocalDateTime t1 = LocalDateTime.now();LocalDateTime t2 = LocalDateTime.of(2024, 7, 8, 0, 0, 0);Duration between = Duration.between(t1, t2);System.out.println("相差的总天数" + between.toDays());System.out.println("相差的总小时数" + between.toHours());System.out.println("相差的总分钟数" + between.toMinutes());System.out.println("相差的总秒数" + between.toSeconds());}
2 异常
2.1 异常的基本使用
Throwable是异常的顶级父类。有两大子类:
- Error 错误 非常严重的问题 需要修改代码才能解决
- StackOverflowError 栈溢出错误 方法递归没有出口时
- OutOfMemoryError 堆内存溢出
- Exception 异常
- 所有异常的父类,程序中出现了一般性的问题,处理异常后程序会继续执行
- 异常分为编译时异常和运行时异常
- 编译时异常在编译阶段需要处理,否则编译不通过
- 运行时异常在编译阶段不需要处理
- RuntimeException和它的子类都是运行时异常
- 其他的异常都是编译时异常
public static void main(String[] args) throws ParseException {
// m1();m(null);}private static void m1() throws ParseException {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");simpleDateFormat.parse("2010/12/12");}public static void m(String str) throws ParseException{if (str == null)
// throw new NullPointerException("空指针异常了,哥们");throw new ParseException("",0);// 出现异常// 1. 创建对应的异常对象 new NullPointerException()// 2. 程序立即停止,并且在控制台显示异常的信息boolean aa = str.equals("aa");System.out.println("HelloWorld");}
2.2 自定义异常
定义一个类,继承Exception(RuntimeException),然后提供无参构造和有参构造,有参构造中调用父类的构造方法
// 自定义异常
// 除了RuntimeException和它的子类,其他都是编译时异常
class PathNotExistException extends Exception{public PathNotExistException(){}public PathNotExistException(String message){super(message);}
}class FileFormatException extends Exception{public FileFormatException(){}public FileFormatException(String message){super(message);}
}
2.3 异常的捕获方式
- 如果出现了多个异常,并且每一个异常的处理方式都不一样,可以使用多个catch分别捕获分别处理。
try {s = readFile("D:\\a.png");} catch (PathNotExistException e) {System.out.println("出现异常了");// 打印异常栈轨迹
// e.printStackTrace();System.out.println(e.getMessage());}catch (FileFormatException e){// 处理异常System.out.println(e.getMessage());}catch (NullPointerException e){System.out.println(e.getMessage());}
- 如果所有异常的处理方式都一样,可以捕获这些异常的父类,然后进行统一的处理。
String s = null;try {s = readFile("D:\\a.png");} catch (Exception e) {System.out.println("出现异常了");// 打印异常栈轨迹
// e.printStackTrace();System.out.println(e.getMessage());}
- 如果异常的处理进行了分组,那么同一组异常之间用| 隔开,进行分组处理
String s = null;try {s = readFile("D:\\a.png");} catch (FileFormatException | PathNotExistException e){// 分组捕获// 处理异常System.out.println(e.getMessage());}catch (NullPointerException e){e.printStackTrace();System.out.println(e.getMessage());}
注意点: 捕获异常的时候应该先捕获子类异常,再捕获父类异常
2.4 异常对方法重写和重载的影响
异常对方法的重载没有影响
class A{public void m()throws IOException{}public void m(int i) throws Exception{}
}
子类抛出的编译时异常不能超过父类对应方法的编译时异常的范围。
运行时异常对于重写没有影响
重写:重写是指在父子类中存在方法签名一致的非静态方法。在构成重写的时候,要求子类重写的方法的权限修饰符的范围要大于等于父类对应方法的权限修饰符范围。如果父类方法的返回值类型是基本数据类型/void,那么子类方法的返回值类型要保持一致。如果父类方法的返回值类型是引用数据类型,那么要求子类方法的返回值类型要么和父类一致,要么是父类方法返回值类型的子类。另外,子类重写的方法抛出的编译时异常不能超过父类对应方法的编译时异常的范围。
重写本身是一种运行时多态。
3 finally
finally修饰代码块,表示无论是否出现异常都会执行的代码块
结果是3
public static int demo1(){try {return 1;}finally {try {return 2;}finally {return 3;}}}
结果是5,7
System.out.println(demo2());// 5}public static int demo2(){int i = 5;try {// 先进入到try中,执行return i++; i是5,先return 5 再 i++// i 变成6// 由于有finally,所以不能理解结束方法,执行finally中的i++// i 变成 7,打印// 然后方法整体结束,返回5return i++;}finally {i++;System.out.println("i = " + i);// 7}}
返回蔡依林 44
public static Person demo3(){Person person = new Person();try {person.setName("周杰伦");person.setAge(45);// 因为返回的是对象,是内存中的一块地址// 由于有finally,继续执行,把上面的地址中的属性值2改成蔡依林 44// 所以最终结果就是 蔡依林 44return person;}finally {
// person = new Person(); 如果这行代码不注释,返回的是周杰伦45person.setName("蔡依林");person.setAge(44);}}
返回的是abc
public static String m(){String str;try {str = "abc";return str;}finally {// 地址已经发生了改变str = "def";}}