8、BigInteger和BigDecimal类
应用场景:
- BigInteger 适合保存比较大的整形
- BigDecimal 适合保存精度更高的浮点型(小数)
8.1 BigInteger和BigDecimal的常用方法
BigInteger:
当我们编程中,需要处理很大的整数,long就不够用了,就可以用BigInteger
-
add 加
- 在对BigInteger 进行加减乘除时,需要使用对应的方法,不能直接进行加减乘除
- 可以创建一个要操作的 BigInteger 然后进行相应的操作
BigInteger bigInteger = new BigInteger("54641132165416484"); BigInteger bigInteger2 = new BigInteger("546"); BigInteger add = bigInteger.add(bigInteger2)
-
subtract 减
-
multiply 乘
-
divide 除
BigDecimal:
当我们需要保存一个精度很高的数时,double 不够用
-
add 加
BigInteger bigInteger = new BigInteger("54641132165416484"); BigInteger bigInteger2 = new BigInteger("546"); BigInteger add = bigInteger.add(bigInteger2)
-
subtract 减
-
multiply 乘
-
divide 除
- 可能抛出异常 ArithmeticException
- 可以在调用devide方法时,指定精度:BigDecimal.ROUND_CEILING,如果有无限循环小数,就会保留 分子(除数) 的精度
System.out.println(bigDecimal.devide(bigDecimal2,BigDecimal.ROUND_CEILING));
9、Date、Calendar、LocalDate...
9.1 第一代日期类
-
Date:精确到毫秒,代表特定的瞬间
- 这里的 Date 类是在 java.util 包
- 默认输入的日期格式是国外的方式,因此通常需要对格式进行转换
Date d1= new Date0;//获取当前系统时间 Date d2=new Date(9234567);//通过指定毫秒数得到时间 System.out.println(d1.getTime()); System.out.println(d2);
-
SimpleDateFormat:格式和解析日期的类
- 格式化和解析日期的具体类。它允许进行格式化(日期 --> 文本)、解析(文本 --> 日期)和规范化
- 创建 SimpleDateFormat 对象,可以指定相应的格式,这里的格式使用的字母不能乱写
- 可以把一个格式化的String转成对应的 Date ,得到Date仍然在输出时,还是依照国外的形式,如果希望指定格式输出,需要转换
- 在把 String ->Date,使用的 sdf 格式需要和你给的 String 的格式一样,否则会抛出转换异常
//日期 --> 文本 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E"); String format = sdf.format(d1);// format:将日期转换成指定格式的字符串//文本 --> 日期 String s = "1996年01月01日 10:20:30 星期一"; Date parse = sdf.parse(s);
9.2 第二代日期类
第二代日期类,主要是 Calendar 类
Calendar:
public abstract class Calendar extends Object implements Serializable,Cloneable, Comparable<Calendar>
- Calendar 类是一个抽象类,并且构造器是私有的 private
- 可以通过 getInstance() 来获取实例
- 它为特定瞬间量一组诸如 YEAR、MONTH、DAY OF MONTH、 HOUR 等日历字段之间的转换提供了一些方法,并为操作日历方法(例如获取下星期的日期)提供了一些方法
- Calendar 没有提供对应的格式化类,因此需要程序员自己组合来输出
- 如果我们需要按照 24 小时进制来获取获取时间
- Calendar.HOUR改成>Calendar.HOUR_OF_Day
应用实例
Calendar c = Calendar.getlnstance(); //创建日历类对象,比较简单,自由
System.out.println(c);//全部信息太长,希望获取某个字段//获取日历对象的某个日历字段
System.out.println("年:" + c.get(Calendar.YEAR));
System.out.println("月:" + (c.get(Calendar.MONTH) + 1));//为什么要 + 1 ? 因为Calendar返回月时,是按 0 开始编号
System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("小时:" + c.get(Calendar.HOUR));
System.out.println("分钟:" + c.get(Calendar.MINUTE));
System.out.println("秒:" + c.get(Calendar.SECOND));//Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
System.out.println(c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月" + c.get(Calendar.DAY_OF_MONTH) + "日");
9.3 第三代日期类
前面两代日期类的不足分析
**JDK 1.0 **中包含了一个java.util.Date类,但是它的大多数方法已经在 JDK 1.1引入
Calendar类之后被弃用了。而Calendar也存在问题是:
- 可变性:像日期和时间这样的类应该是不可变的
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始
- 格式化:格式化只对Date有用,Calendar则不行
- 此外,它们也不是线程安全的;不能处理闰秒等(每隔2天,多出1s)
第三代日期类常用方法:JDK8加入
(1):
LocalDate(日期 / 年月日)、LocalTime(时间 / 时分秒)、LocalDateTime(日期时间)
- LocalDate只包含日期,可以获取日期宇段
- LocalTime只包含时间,可以获取时间字段案例演示
- LocalDateTime包含日期+时间,可以获取日期和时间字段
解读:
- 使用new(),返回表示当前日期时间的对象
LocalDateTime ldt = LocalDateTime.now(); //或是LocalDate.now(); //LocalTime.now();
System.out.printin(ldt);System.out.printin(ldt.getYear());
System.out.printin(ldt.getMonth()); //返回月份的英文
System.out.printin(ldt.getMonthValue()); //返回月份的数字
......
(2):
DateTimeFormatter格式日期类
- 类似于SimpleDateFormat,使用 DateTimeFormatter 对 LocalDateTime 进行格式化
案例演示:
- 创建 DateTimeFormatter 对象
LocalDateTime ldt = LocalDateTime.now();//关于DateTimeFormatter 的各个格式参数,需要看jdk8的文档.DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
String strDate = dateTimeFormatter.format(ldt);
(3):
Instant 时间戳
- 类似于Date,提供了一系列和Date类转换的方式
Instant->Date:
Date date = Date.from(instant);
Date>Instant:
Instant instant =date.tolnstant();
//通过静态方法 now() 获取表示当前时间戳的对象
Instant now = Instant.now();
System.out.println(now);//通过 from 可以把 Instant 转成Date
Date date = Date.from(now);//通过 date 的toInstant() 方法,可以把 date 转成 Instant对象
Instant instant = date.tolnstant();
(4):
第三代日期类更多方法
-
LocalDateTime类
-
MonthDay类:检查重复事作
-
是否是闰年
-
增加日期的某个部分
-
使用plus方法测试增加时间的某个部分
LocalDateTime ldt = LocalDateTime.now(); LocalDateTime localDateTime = ldt.plusDays(999);
-
使用minus方法测试查看一年前和一年后的日期
LocalDateTime ldt = LocalDateTime.now(); LocalDateTime localDateTime = ldt.minusDays(999);
10、练习
一、String翻转
(1)将字符串中指定部分进行反转。比如将”abedef"反转为"aedcbf"
(2)编写方法 public static String reverse(String str, int start, int end) 搞定
思路分析:
-
先把方法定义确定
-
把 String 转成 char[] ,因为 char[] 的元素是可以交换的
-
画出分析示意图

-
代码实现
public static String reverse(String str, int start, int end){//对输入的参数做一个验证//重要的编程技巧:写出正确的情况,然后取反即可if(!(str != null && start >= 0 && end > start && end < str.length())){throw new RuntimeException("参数不正确");}char[] chars = str.toCharArray();char temp=''; //交换辅助变量for (int i = start, j= end; i < j; i++, j--){temp = chars[i];chars[i]= chars[j];chars[j]= temp;}//使用chars 重新构建一个String 返回即可return new String(chars);
}
二、注册处理
输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
要求:
(1)用户名长度为2或3或4
(2)密码的长度为6,要求全是数字
(3)邮箱中包含@和. 并且@在.的前面 isDigital
思路分析:
- 先编写方法 userRegister( String name , String pwd , String email ){}
- 针对输入的内容进行校核,如果发现有问题,就抛出异常,给出提示
- 单独的写一个方法,判断 密码是否全部是数字
public static void userRegister( String name , String pwd , String email ){//过关//第一关int userLength = name.length();if(!(userLength >= 2 && userLength <= 4)){throw new RuntimeException("用户名长度为2或3或4");}//第二关if(pwd.length() == 6 && isDigital(pwd)){throw new RuntimeException("密码的长度为6,要求全是数字");}//第三关int i = email.indexOf('@');int j = email.indexOf('.');if(!(i > 0 && j > i)){throw new RuntimeException("邮箱中包含@和.,并且@在.的前面");}}
public static boolean isDigital(String str){char[] chars = str.tocharArray();for(int i=0; i< chars.length; i++) {if(chars[i] <'0' || chars[i] >'9'){return false;}} return true;
}
三、
(1)编写java程序,输入形式为:Han Shun Ping的人名,以Ping,Han .S的形式打印出来,其中.S是中间单词的首字母。
(2)例如输入"Willian Jefferson Clinton”,输出形式为:Clinton, Willian. J
思路分析:
- 对输出的字符串进行 分割 split(" ")(比索引空格快)
- 对得到的String[] 进行格式化 Strinhg.format()
- 对输入的字符串进行校验
public void printName(String str){if(str == null){System.out.println("str 不能为空");return;}String[] names = str.split(" ");if(names.length != 3){System.out.println("输入的字符串格式不对");return;}String format = String.format("%s, %s .%c", names[2], names[0], names[1].toUpperCase().charAt(0));System.out.println(format);
}
四、字符串统计
输入一个字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字
思路分析:
- 遍历字符串,如果 char 在‘@'~'9',就是一个数字
- 如果 char 在'a'~'z’,就是一个小写字母
- 如果 char 在'A'~'Z',就是一个大写字母
- 使用三个变量来记录数据
public static void countStr(String str){if (str == null) {System.out.println("输入不能为 null");return;}int strLen = str.length();int numCount = 0;int LowerCount = 0;int upperCount = 0;int otherCount = 0;for (int i = 0; i< strLen; i++){if(str.charAt(i) >='0' && str.charAt(i) <= '9'){numCount++; } else if(str.charAt(i) >= 'a' && str.charAt(1)<='2'){lowerCount++;} else if(str.charAt(1) >= 'A' && str.charAt(i) <=·Z'){upperCount++;}else {otherCount++;}}System.out.println(...); ... //输出
}
五、String类的内存布局
试着写出运行结果
已知Animal类有属性name,可以通过有参构造为属性赋值
class Animal {String name;public Animal(String name){this.name= name;}
}
String s1="hspedu";
Animal a = new Animal(s1);
Animal b = new Animal(s1);
System.out.println(a==b); //false
System.out.println(a.equals(b)); //false,调用animal的equals,但equals没有重写
System.out.println(a.name == b.name); //trueString s4 = new String("hspedu");
String s5 = "hspedu";System.out.println(s1 == s4); //false
System.out.println(s4 == s5); //falseString t1 = "hello" + s1;
String t2 = "hellohspedu";
System.out.printin(t1.intern() == t2); //true
