工具类
1 数学类
1.1 BigInteger类
用于进行大量数字存储和计算的类
public static void main(String[] args) {
// 用于大量数值的存储和计算
BigInteger bigInteger = new BigInteger("456463546335465436757657564765474657654765846786786576576576576547654765476547456463546335465436757657564765474657654765846786786576576576576547654765476547456463546335465436757657564765474657654765846786785436757657564765474657654765846786786576576576576547654765476547");
BigInteger bigInteger1 = new BigInteger("4564635463354654367576575647654746576547658467867865765765765765476547654765474564635463354463546335465436757657564765474657654765");
// 乘
System.out.println(bigInteger.multiply(bigInteger1));
// 加
System.out.println(bigInteger.add(bigInteger1));
// 除
System.out.println(bigInteger.divide(bigInteger1));
System.out.println(bigInteger.subtract(bigInteger1));
}
1.2 BigDecimal类
用于精确运算的类,要求参数以字符串形式传递
private static void demo2() {
// 在java中是不能进行精确运算
// double d = 3.00;
// double d1 = 2.99;
// System.out.println(d - d1);
// 这里想要精确计算,必须使用字符串存储,底层会按照小数点进行按位运算
BigDecimal bigDecimal = new BigDecimal("3.00");
BigDecimal bigDecimal1 = new BigDecimal("2.99");
System.out.println(bigDecimal.subtract(bigDecimal1));
}
1.3 DecimalFormat类
这个类用于数字固定格式转换
private static void demo3() {
double d = 50.89 * 0.81;
System.out.println(d);
// 创建对象并且指定数据显示的格式
// 用0来表示占位,表示一个数字,如果这一位没有数字,用0代替
// #代表占位,表示一位数字,如果这一位没有数字,那么就不填充内容。如果有数字就填充内容。
// 0#.00会直接抛出异常,因为不符合常理
// DecimalFormat decimalFormat = new DecimalFormat("#0.00");
// 科学计数法
DecimalFormat decimalFormat = new DecimalFormat("0.0E0");
System.out.println(decimalFormat.format(d));
}
1.4 面试题分享
- 两个千位数字相乘,有几种解决方案?
- BigInteger类可以轻松解决
- 还有没有其他解决方案?
分析:怎么存储?
String或者数组.
怎么乘?
int[] arr1 = {1, 9, 9, 8};
int[] arr2 = {1, 7, 7, 6};
int[] arr3 = new int[arr1.length + arr2.length];
for (int i = 0; i < arr2.length; i++) {
for (int j = 0;j < arr1.length;j++){
arr3[i + j] += arr2[j] * arr1[i];
}
}
for(int i = arr3.length - 2;i > 0;i--){
int temp = arr3[i];
arr3[i] = arr3[i] % 10;
arr3[i - 1 ] += (temp / 10);
}
if(arr3[0] >= 10){
int[] arr4 = new int[arr3.length];
arr4[0] = arr3[0] / 10;
arr4[1] = arr3[0] % 10;
int[] arr5 = Arrays.copyOfRange(arr3,1,arr3.length - 1);
System.arraycopy(arr5,0,arr4,2,arr5.length);
System.out.println(Arrays.toString(arr4));
}else {
int[] arr4 = Arrays.copyOfRange(arr3,0,arr3.length - 1);
System.out.println(Arrays.toString(arr4));
}
日期&异常
1 日期
1.1 日期Date类的格式化
- 日期转换成字符串
public static void main(String[] args) {
// 获取当前时间
Date date = new Date();
System.out.println(date);
// 创建日期格式化对象 2023-08-29 10:13:59
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS EE a");
String str = simpleDateFormat.format(date);
System.out.println(str);
}
- 字符串转日期
public static void main(String[] args) throws ParseException {
// 1999-12-01
// 字符串转日期
String str = "1999-12-01";
// 创建日期格式化对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = simpleDateFormat.parse(str);
System.out.println(date);
}
1.2 日历类
private static void demo3() {
// 获取当前时间的日历类
Calendar calendar = Calendar.getInstance();
System.out.println(calendar);
// field : 属性
int year = calendar.get(Calendar.YEAR);
System.out.println("年是" + year);
int month = calendar.get(Calendar.MONTH);
System.out.println("月是" + (month + 1));
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("日是" + day);
Date date = new Date(1234242354345L);
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
System.out.println(date);
// 设置日历类的时间
calendar.setTime(date);
System.out.println(calendar.get(Calendar.YEAR));
System.out.println(calendar.get(Calendar.WEEK_OF_MONTH));
}
练习:上海股市每一个月的第三周的周六进行交易,其他时间是无法交易的。输入一个时间(2024-09-01),判断这个时间是否允许交易并提示:交易未开始,交易已结束,交易正在进行中。
private static void practice01() throws ParseException {
// 上海股市每一个月的第三周的周六进行交易,其他时间是无法交易的。
// 输入一个时间(2024-09-01),判断这个时间是否允许交易并提示:交易未开始,交易已结束,交易正在进行中。
// 1.用户输入一个字符串时间
System.out.println("请输入您想查询的日期");
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
// 2.把字符串时间转换成日期对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = simpleDateFormat.parse(str);
// 3.设置日历对象的日期
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
// 4.获取第几周,获取周几
// DAY_OF_WEEK_IN_MONTH从把1号看作这个月的第一周
// 第几周
int week = calendar.get(Calendar.WEEK_OF_MONTH);
// 周几
int day = calendar.get(Calendar.DAY_OF_WEEK);
// 5.判断
if (week == 3 && day == 7){
System.out.println("交易正在进行中");
}else if(week < 3 || week == 3 && day < 7){
System.out.println("交易未开始");
}else {
System.out.println("交易已结束");
}
}
1.3 java.time包
在JDK1.8之后,对时间体系进行了新的划分,将日期和时间以及其他的信息进行分割,从而分出来一个代表时间的包–java.time
1.3.1 LocalDate
这个类中只能表示年月日,没有时分秒
private static void demo4() {
// 获取当前日期
LocalDate date = LocalDate.now();
System.out.println(date);
// 指定日期
LocalDate date1 = LocalDate.of(1998, 2, 28);
System.out.println(date1);
// 增加时间
date1 = date1.plus(3, ChronoUnit.DAYS);
System.out.println(date1);
// 减少时间
System.out.println(date1.minus(10, ChronoUnit.MONTHS));
}
1.3.2 LocalTime
这个类中只能表示时分秒毫秒微妙纳秒,没有日期
// LocalTime
// 获取当前时间
LocalTime now = LocalTime.now();
System.out.println(now);
// 指定时间
LocalTime of = LocalTime.of(10, 25, 9);
System.out.println(of);
// 增加时间
of = of.plus(3, ChronoUnit.HOURS);
System.out.println(of);
// 减少时间
System.out.println(of.minus(4, ChronoUnit.HOURS));
1.3.3 LocalDateTime
这个类中有年月日时分秒毫秒微妙纳秒
private static void demo6() {
// 获取当前年月日时分秒毫秒纳秒
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(dateTime);
// 指定时间
LocalDateTime of = LocalDateTime.of(2019, 9, 10, 10, 1);
System.out.println(of);
// 增加时间
System.out.println(dateTime.plus(3, ChronoUnit.YEARS));
// 减少时间
System.out.println(dateTime.minus(4,ChronoUnit.MINUTES));
}
1.3.4 Instant类
Instant类是JDK8中推荐用来替换Date类。可以精确到纳秒。Date类只能精确到毫秒。
private static void demo7() {
// 默认获取的是世界时间
Instant now = Instant.now();
System.out.println(now);
// 获取北京时间
// now = now.plus(8,ChronoUnit.HOURS);
// now = now.plusSeconds(8 * 60 * 60);
// System.out.println(now);
// 获取毫秒
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));
// 转换成LocalDateTime ZoneId.systemDefault(): 默认系统时区
LocalDateTime localDateTime = LocalDateTime.ofInstant(now, ZoneId.systemDefault());
System.out.println(localDateTime);
}
1.3.5 字符串和JDK8日期类型转换
- LocalDate和String相互转换
private static void demo8() {
LocalDate date1 = LocalDate.of(2023,8,29);
System.out.println(date1);
// 日期格式化对象
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String format = timeFormatter.format(date1);
System.out.println(format);
// 字符串转日期
LocalDate parse = LocalDate.parse(format, timeFormatter);
System.out.println(parse);
}
- LocalDateTime和String相互转换
private static void demo9() {
// 日期转字符串
LocalDateTime localDateTime = LocalDateTime.of(2023,8,29,15,13,20);
System.out.println(localDateTime);
// 日期转换对象
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String format = dateTimeFormatter.format(localDateTime);
System.out.println(format);
// 字符串转日期
LocalDateTime parse = LocalDateTime.parse(format,dateTimeFormatter);
System.out.println(parse);
}
2 异常
2.1 异常介绍
异常和错误有一个顶级的父类Throwable.
Throwable有两个子类
- Error错误
- 是所有错误的父类,表示程序中出现了非常严重的问题,不修改源码程序不能执行
- Exception异常
- 表示所有异常的父类,程序中出现了一般性的问题,程序员处理后代码可以继续向下执行
- 异常分为编译时异常和运行时异常
- 不是RuntimeException及其子类的异常都是编译时异常
- 编译时异常在编译期间就会报错,必须处理。
- 运行时异常在运行时会出错,编译期间不需要处理
2.2 throw和throws用法
throw是在方法内部手动new一个异常,告诉调用者
throws是声明可能遇到的异常,但是不处理,让别人处理
public static void main(String[] args) throws ParseException {
int[] arr = {1,2,3,4,5,6};
int element = getElement(arr);
System.out.println(element);
}
public static int getElement(int[] arr) throws ParseException {
// 数组中没有对应5的索引,JVM检测到出现了问题,JVM就会创建一个异常对象
// 这个异常会抛出给调用的方法,就是main方法
// main方法收到了异常,main方法自己不会处理,main方法接着将异常抛出去给JVM
// JVM不会处理,做了2件事情
// 1。就是把异常的信息打印在控制台
// 2. 停止程序
// throw new ArrayIndexOutOfBoundsException();
if (arr == null){
throw new NullPointerException("数组arr是一个null");
}
if (arr.length < 6) {
throw new ArrayIndexOutOfBoundsException("数组的长度不合法");
}
method();
return arr[5];
}
public static void method() throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy");
simpleDateFormat.parse("");
}
2.3 自定义异常
自定义异常需要继承Exception或者其子类。
如果继承了RuntimeException就是一个运行时异常
如果继承的不是RuntimeException就是编译时异常
自定义异常需要提供一个无参构造和一个有参构造,有参构造中直接调用父类的有参构造方法
class FileFormatException extends Exception{
public FileFormatException(){}
public FileFormatException(String message){
super(message);
}
}
// 自定义异常 如果继承RuntimeException 就是一个运行时异常
// 如果没有继承RuntimeException及其子类,那么就是一个编译时异常
class PathNotExistException extends Exception{
public PathNotExistException(){}
public PathNotExistException(String message){
super(message);
}
}
2.4 捕获异常
使用try…catch可以捕获编译时和运行时异常
在try编写可能会出现异常的代码,catch中处理异常
/**
* 可以使用try{}catch{}来捕获异常,从而处理异常
* 格式:
* try{
* 被检测的代码,有可能出现异常的代码;
* }catch(要捕获的异常类 变量名){
* 对于异常的处理方法(写循环,判断,调用方法...)
* 只要代码到catch中,说明已经已经处理了,代码就可以继续向下执行了
* }
* try中出现异常,程序执行catch,代码会继续向下执行
* try中出现异常,程序不执行catch,代码不会继续向下执行
* 如果捕获到异常,会把异常的对象赋值给catch中的变量
*/
String str = null;
try {
str = readTxt("E:\\a.jpg");
} catch (PathNotExistException e) {
// getMessage()获取异常的信息
System.out.println(e.getMessage());
}catch (NullPointerException e){
System.out.println(e.getMessage());
} catch (FileFormatException e) {
// 打印异常的栈轨迹
e.printStackTrace();
}
System.out.println("程序继续向下执行");
System.out.println(str);
案例
public static void main(String[] args) {
System.out.println(parseText("1998/04/17"));
}
// 假设公司一种日期表示格式是用- 一种使用/
public static Date parseText(String str){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = simpleDateFormat.parse(str);
} catch (ParseException e) {
simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
try {
date = simpleDateFormat.parse(str);
} catch (ParseException ex) {
}
}
return date;
}
2.5 异常的捕获方式
- 如果出现了多个异常,并且每一个异常的处理方式都不一样,可以使用多个catch分别捕获来处理。
String str = null;
try {
str = readTxt("E:\\a.jpg");
} catch (PathNotExistException e) {
// getMessage()获取异常的信息
System.out.println("修改文件路径");
System.out.println(e.getMessage());
}catch (NullPointerException e){
System.out.println("重新赋值");
System.out.println(e.getMessage());
} catch (FileFormatException e) {
System.out.println("修改文件格式");
// 打印异常的栈轨迹
e.printStackTrace();
}
System.out.println("程序继续向下执行");
System.out.println(str);
- 如果所有的异常的处理方式都一样,可以捕获这些异常的共同的父类,然后在一个catch中统一处理
String str = null;
try {
str = readTxt("E:\\a.jpg");
} catch (Exception e) {
// 打印异常的栈轨迹
e.printStackTrace();
}
System.out.println("程序继续向下执行");
System.out.println(str);
- 如果异常的处理进行了分组,那么同一组异常之间用|隔开,从而可以分组处理
- JDK1.7后可以使用
String str = null;
try {
str = readTxt("E:\\a.jpg");
} catch (PathNotExistException e) {
System.out.println("文件不存在异常");
}catch (NullPointerException | FileFormatException e){
// 打印异常的栈轨迹
e.printStackTrace();
}
System.out.println("程序继续向下执行");
System.out.println(str);
注意: 捕获异常的时候需要先捕获子类,再捕获父类
String str = null;
try {
str = readTxt("E:\\a.jpg");
}catch (NullPointerException e){
// 打印异常的栈轨迹
e.printStackTrace();
} catch (FileFormatException e) {
// 打印异常的栈轨迹
e.printStackTrace();
} catch (Exception e) {
System.out.println("文件不存在异常");
}
System.out.println("程序继续向下执行");
System.out.println(str);
如果先捕获Exception,已经包含了NullPointerException和FileFormatException,所有后面的捕获异常等于没有写
2.6 异常对于方法重写和重载的影响
- 异常对于重载没有影响。
- 在方法重写的时候,子类抛出的编译时异常不能超过父类对应方法的编译时异常的范围
class A {
public void m()throws IOException {
}
public void m(int i) throws ParseException{
}
}
class B extends A{
// 因为FileNotFoundException是IOException的子类
public void m() throws FileNotFoundException {
}
}
2.7 finally
用于修饰代码块,被finally修饰的代码块无论是否出现异常都一定会执行
try {
System.out.println(1 / 0);
} finally {
System.out.println("finally...");
}
System.out.println("hello");
try-catch和finally连用时,在编译阶段会认为try中的代码不一定执行
String str;
try {
str = "abc";
}catch (Exception e){
} finally{
System.out.println("finally...");
}
// java认为str在try中可能会出现异常,所以这里编译失败
System.out.println(str);
System.out.println("hello");
2.8 面试题
- 第一种情况 结果是7和9
public static int demo02(){
/**
* 代码是从上到下编译和运行的
* 先进入到try代码块中,然后获取i的值是7,由于++符号在i的后面
* 所以JVM先标记i的值为7,然后进行return操作,i自增为8
* 在要return标记值7的时候,受到try的影响,要检查下有没有finally代码块
* 检查到有finally,继续执行,i++,结果是9
* 如果finally中的代码是return i++,那么就会将第一次自增后的8返回出去
*/
int i = 7;
try {
return i++;
}finally {
i++;
System.out.println("finally中的i的值是" + i);
}
}
- 第二种情况 结果是 8 8
public static int demo02(){
/**
* 代码是从上到下编译和运行的
* 先进入到try代码块中,然后获取i的值是7,由于++符号在i的后面
* 所以JVM先标记i的值为7,然后进行return操作,i自增为8
* 在要return标记值7的时候,受到try的影响,要检查下有没有finally代码块
* 检查到有finally,继续执行,i++,结果是9
* 如果finally中的代码是return i++,那么就会将第一次自增后的8返回出去
*/
int i = 7;
try {
return i++;
}finally {
System.out.println("finally中的i的值是" + i);
return i++;
}
}
- 情况三
private static Person demo03() {
Person person = new Person();
try {
person.setName("刘翔");
person.setAge(20);
// 因为返回的是一个对象,是同一个地址
// 在执行finally时,会将同一个地址person中的属性修改。所以结果是姚明
return person;
}finally {
person.setName("姚明");
person.setAge(30);
}
}
- 情况四
private static Person demo03() {
Person person = new Person();
try {
person.setName("刘翔");
person.setAge(20);
// 0x111
return person;
}finally {
// 0x222
// 这种情况结果是刘翔
person = new Person();
person.setName("姚明");
person.setAge(30);
}
}
- 情况五
private static String demo04() {
String str;
try {
str = "abc";
return str;
}finally {
// 地址已经发生改变,所以返回的str还是原来的abc
str = "def";
}
}