目录
12.1 LocalDate、LocalTime、LocalDateTime
12. 2 ZoneId:时区、ZonedDateTime:带时区的时间
12.4 DateTimeFormatter(线程安全):格式化器,用于时间的格式化、解析
12.5 Period:计算日期间隔(年,月,日)、Duration:计算时间间隔(时、分、秒,纳秒)
方式一:让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。
方式二:使用下面这个sort方法,创建comparator比较器接口的匿名内部类对象,然后自己制定比较规则。
前言
常用API笔记复盘【未完】(目前更新至2024.6.2),由于该篇文档字多太多,导致卡顿,后面的笔记会接续到常用API(二)中
一、包的概述
1.同一个包下的程序,可以直接访问
2.访问其他包下的程序,必须导包才可以访问
3.自己在编写程序过程中调用java提供的程序,也需要先导包才可以使用;注意:java.lang包下的程序是不需要导包的,可以直接使用
4.访问多个其他包下的程序,这些程序名又是一样的情况下,默认只能导入一个程序,另一个程序必须带包名和类名访问
二、String
2.1 String概述
1.String可以做什么?
代表字符串,用来创建对象封装字符串数据,并对其处理
2.String类创建对象封装字符串的方式有几种?
(1)直接引用双引号
(2)new String,调用初始化字符串对象。
2.2 String常用的方法
package String;
public class StringDemo {
public static void main(String[] args) {
String s = "黑马java";
//1、获取字符串的长度
System.out.println(s.length());
//2、提取字符串中的某个索引位置的字符
char c = s.charAt(1);
System.out.println(c);
//字符串遍历
for (int i = 0; i < s.length() ;i++) {
char ch=s.charAt(1);
System.out.println(ch);
}
System.out.println("==========================");
//3、字符串转换成字符数组,在进行遍历
char [] chars=s.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
//4、判断字符串内容,内容一样就返回true
String s1=new String("黑马");
String s2=new String("黑马");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
//5、忽略大小写比较字符串内容
String c1="34AeFG";
String c2="34aeFG";
System.out.println(c1.equals(c2));//false
System.out.println(c1.equalsIgnoreCase(c2));//true
//6、截取字符串内容(包前不包后)
String s3="Java是最好的编程语言之一";
String rs=s3.substring(0,8);
System.out.println(rs);
//7、从当前索引位置一直字符串末尾
String rs2=s3.substring(5);
System.out.println(rs2);
//8、把字符串中的某个内容替换成新内容,并返回字符串对象给我们
String info="这个电影简直是个垃圾,垃圾电影!!";
String rs3=info.replace("垃圾","**");
System.out.println(rs3);
//9、判断字符串中是否包含某个关键字,包含为true 不包含为false
String info2="Java是最好的编程语言之一,,我爱Java,Java不爱我";
System.out.println(info2.contains("Java"));
System.out.println(info2.contains("java"));
System.out.println(info2.contains("Java2"));
//10、判断字符串是否是以某个字符串开头
String rs4="张三丰";
System.out.println(rs4.startsWith("张"));
System.out.println(rs4.startsWith("张三"));
System.out.println(rs4.startsWith("张三2"));
//11、把字符串按照某个指定内容分割成多个字符串,放到一个字符串数组中返回
String rs5="张无忌,周子正,殷素素,赵敏";
String[] names=rs5.split(",");
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
}
}
2.3 String的注意事项
1.String的对象是不可变的对象,他只是地址的改变,里面的内容是不变的,类如下方例子就是字符串的拼接
2.
- 只要是以" "方式写出来的字符串的对象,会存储到字符串的常量池中,且相同的字符串内容只能存储一份
- 通过new方式创建的字符串对象,每new一次就是产生新的字符串对象放在一个堆内存中
常见面试题:
上图中s2是符号(变量)所以不能拼接
2.4 String应用案例
1.用户登录
package String;
import java.util.Scanner;
//用户登录案例
public class StringTest {
//1、登陆界面
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Scanner scanner = new Scanner(System.in);
System.out.println("请您输入登录名称:");
String loginName = scanner.next();
System.out.println("请您输入登录密码:");
String passWord = scanner.next();
//5、调用登录方法,判断是否登录成功
boolean rs = login(loginName, passWord);
if (rs) {
System.out.println("恭喜您,欢迎进入系统");
break;//跳出for循环,代表登录成功
} else {
System.out.println("登录名或者密码错误,请重新输入");
}
}
}
public static boolean login(String loginName, String passWord) {
//3、准备一份系统正确的名称和密码
String okLoginName = "itheima";
String okPassWord = "123456";
//4、开始正式判断用户是否登录成功
/*if (okLoginName.equals(loginName) && okPassWord.equals(passWord)) {
//登录成功
return true;
} else
return false;*/
return okLoginName.equals(loginName) && okPassWord.equals(passWord);
}
}
2.验证码
package String;
import java.util.Random;
public class StringTest2 {
public static void main(String[] args) {
System.out.println(createCode(4));
System.out.println(createCode(6));
}
//1、返回指定位数的验证码
public static String createCode(int n) {
//2、定义2个变量,一个是记住最终产生的随机验证码,一个是记住可能用到的的全部字符
String code = "";
String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMHOPQRSTUVWXYZ123456789";
//3、定义一个循环产生随机字符
Random r = new Random();
for (int i = 0; i < n; i++) {
//4、随机一个字符范围内的索引
int index = r.nextInt(data.length());
//5、根据索引去全部字符中提取该字符
code += data.charAt(index);
}
//返回code验证码
return code;
}
}
三、ArrayList
3.1 ArrayList概述
1.集合是什么?
- 一种容器,用来存储数据
- 集合的大小可变
2.ArrayList是什么?怎么使用?
- 是结合中最常用的一种,ArrayList是泛型类,可以约束存储的类型
- 创建对象,调用无参数构造函数初始化对象:public ArrayList();
- 调用相应的增删改查数据
3.ArrayList提供的方法:
package ArrayList;
import java.util.ArrayList;
public class ArrayListDemo1 {
public static void main(String[] args) {
//1、创建一个ArrayList集合对象
// ArrayList<String> list=new ArrayList<String>();
//从1.7版本开始支持
ArrayList<String> list=new ArrayList<>();
list.add("黑马");
list.add("Java");
System.out.println(list);
//2、在索引中某个位置添加一个数据
list.add(1,"MySQL");
System.out.println(list);
//3、根据索引获取集合中的某个索引位置的值
String rs=list.get(1);
System.out.println(rs);
//4、获取集合的大小(返回集合中存储元素的个数)
System.out.println(list.size());
//5、根据索引删除集合中的某个元素,会返回删除元素
System.out.println(list.remove(1));
//6、直接删除集合中的某个元素,删除成功会返回true,反之返回false
System.out.println(list.remove("Java"));
//注:如果有相同元素 在删除时,首先删除时第一次出现的元素
//7、修改某个索引位置处的数据,修改后会返回
System.out.println(list.add("123"));
System.out.println(list);
System.out.println(list.set(1 ,"黑马程序员"));
System.out.println(list);
}
}
3.2 ArrayList应用案例
package ArrayList;
import java.util.ArrayList;
public class ArrayListTest2 {
public static void main(String[] args) {
//1、 创建一个ArrayList集合对象
ArrayList<String> list = new ArrayList<>();
list.add("Java入门");
list.add("宁夏枸杞");
list.add("黑枸杞");
list.add("人字拖");
list.add("特技枸杞");
list.add("枸杞子");
System.out.println(list);
//2、从集合中找出包含枸杞的数据,并删除
//方式一:在move后面添加i-- 退一格继续查找并删除
/* for (int i = 0; i < list.size(); i++) {
//i=0 1 2 3 4 5
//取出当前遍历到的数据
String ele = list.get(i);
//判断数据中包含的枸杞
if (ele.contains("枸杞")) {
//直接从集合中删除数据
list.remove(ele);
i--;
}
}
System.out.println(list);*/
//方式二:倒着删
for (int i = list.size() - 1; i >= 0; i--) {
String ele=list.get(i);
if(ele.contains("枸杞")){
list.remove(ele);
}
}
System.out.println(list);
}
}
3.3 ArrayList综合案例
1.创建一个Food类,存放数据
package AarryListDemo;
public class Food {
private String name;
private double originalPrice;
private double specialPrice;
private String info;
public Food() {
}
public Food(String name, double originalPrice, double specialPrice, String info) {
this.name = name;
this.originalPrice = originalPrice;
this.specialPrice = specialPrice;
this.info = info;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getOriginalPrice() {
return originalPrice;
}
public void setOriginalPrice(double originalPrice) {
this.originalPrice = originalPrice;
}
public double getSpecialPrice() {
return specialPrice;
}
public void setSpecialPrice(double specialPrice) {
this.specialPrice = specialPrice;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
2.创建一个FoodManager类,用于处理菜品的功能,和商家管理系统
package AarryListDemo;
import java.util.ArrayList;
import java.util.Scanner;
public class FoodManager {
//1、创建一个Food的集合
ArrayList<Food> foods = new ArrayList<>();
Scanner sc = new Scanner(System.in);
public void add() {
System.out.println("==========菜品上架==========");
//提前创建一个菜品对象,用于封装用户商家的菜品信息
Food food = new Food();
System.out.println("请输入需要上架的名称:");
String name = sc.next();
food.setName(name);
System.out.println("请输入需要上架的原价:");
double originalPrice = sc.nextDouble();
food.setOriginalPrice(originalPrice);
System.out.println("请输入需要上架的优惠价:");
double specialPrice = sc.nextDouble();
food.setSpecialPrice(specialPrice);
System.out.println("请输入需要上架的其他信息:");
String info = sc.next();
food.setInfo(info);
//3、把菜品添加到集合容器中
foods.add(food);
System.out.println("恭喜您上架成功!");
}
//2、菜品浏览功能
public void printAllFood() {
for (int i = 0; i < foods.size(); i++) {
Food food = foods.get(i);
System.out.println("菜品的名称:" + food.getName());
System.out.println("菜品的原价:" + food.getOriginalPrice());
System.out.println("菜品的优惠价:" + food.getSpecialPrice());
System.out.println("菜品的其他信息:" + food.getInfo());
System.out.println("==============================================");
}
}
/**
* 专门负责展示系统界面的
*/
public void start() {
while (true) {
System.out.println("================欢迎进入商家后台管理系统=================");
System.out.println("1.上架菜品(add)");
System.out.println("2.浏览菜品(query)");
System.out.println("3.退出系统(exit)");
System.out.println("请选择您要操作的命令:");
String command =sc.next();
switch (command){
case "add":
add();
break;
case "query":
printAllFood();
break;
case "exit":
return;
default:
System.out.println("您输入的命令有错误,请重新输入!");
}
}
}
}
3.Test类测试数据
package AarryListDemo;
public class Test {
public static void main(String[] args) {
FoodManager foodManager=new FoodManager();
foodManager.start();
}
}
四、Object类
Object类是java中所有类的祖宗类,因此,Java中所有类的对象都可以直接使用0bject类中提供的一些方法
常见方法:
- toString存在的意义:toString()方法存在的意义就是为了被子类重写,以便返回对象具体的内容。
- equals存在的意义:直接比较两个对象的地址是否相同完全可以用“==”替代equals,equals存在的意义就是为了被子类重写,以便子类自己来定制比较规则(比如比较对象内容)。
Student.class
package d1_api_object;
import java.util.Objects;
public class Student {//extend Object
private String name;
private int age;
//重写equal方法,比较两个对象内容一样返回true
@Override
//重写equals方法,比较两个对象的内容一样就返回true
//比较者:s2==this
//被比较者:s1==0
public boolean equals(Object o) {
//1、判断两个对象是否地址一样,一样直接返回true.
if (this == o) return true;
//2、判断o是null直接返回false,或者比较者的类型与被比较者的类型不一样,返回false
// Student.class !=???.class
if (o == null || getClass() != o.getClass()) return false;
// 3、o不是null,且o一定是学生类型的对象。开始比较内容了!
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student() {
}
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 Student(String name, int age) {
this.name = name;
this.age = age;
}
}
Test.class
package d1_api_object;
public class Test {
public static void main(String[] args) {
Student s1 = new Student("张三", 18);
System.out.println(s1);
Student s2 = new Student("张三", 18);
System.out.println(s2.equals(s1));
System.out.println(s2==s1);
}
}
1、Object中tostring方法的作用是什么?存在的意义是什么?
- 基本作用:返回对象的字符串形式。
- 存在的意义:让子类重写,以便返回子类对象的内容。
2、Object中equals方法的作用是什么?存在的意义是什么?
- 基本作用:默认是比较两个对象的地址是否相等。
- 存在的意义:让子类重写,以便用于比较对象的内容是否相同。
当某个对象调用这个方法时,这个方法会复制一个一模一样的新对象返回
1、浅克隆
拷贝出的新对象,与原对象中的数据一模一样(引用类型拷贝的只是地址)
User.class
package d1_api_object;
//Cloneable是一个标记接口
//规则
public class User implements Cloneable {
private int id;//编号
private String username;//用户名
private String password;//密码
private double[] scores;//分数
@Override
protected Object clone() throws CloneNotSupportedException {
//super去调用父类0bject中的clone方法:
return super.clone();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 double[] getScores() {
return scores;
}
public void setScores(double[] scores) {
this.scores = scores;
}
public User() {
}
public User(int id, String username, String password, double[] scores) {
this.id = id;
this.username = username;
this.password = password;
this.scores = scores;
}
}
Test2.class
package d1_api_object;
public class Test2 {
public static void main(String[] args) throws CloneNotSupportedException {
User u1 = new User(1, "zhangsan", "wo666", new double[]{99.0, 99.5});
System.out.println(u1.getId());
System.out.println(u1.getUsername());
System.out.println(u1.getPassword());
System.out.println(u1.getScores());
System.out.println(u1.getClass());
User u2 = (User) u1.clone();
System.out.println(u2.getId());
System.out.println(u2.getUsername());
System.out.println(u2.getPassword());
System.out.println(u2.getScores());
System.out.println(u2.getClass());
}
}
2、深克隆
- 对象中基本类型的数据直接拷贝
- 对象中的字符串数据拷贝的还是地址
- 对象中还包含的其他对象,不会拷贝地址,会创建新对象
-
@Override protected Object clone() throws CloneNotSupportedException { //super去调用父类0bject中的clone方法: User u2= (User) super.clone(); u2.scores=u2.scores.clone(); return u2; }
五、Objects类
Objects是一个工具类,提供了很多操作对象的静态方法给我们使用。
Test.class
package d2_api_objects;
import java.util.Objects;
public class Test {
public static void main(String[] args) {
String s1 = null;
String s2 = "itheima";
// System.out.println(s1.equals(s2));
//为什么使用objects.equals来判断,因为不会如果有null值的判断执行时并不会报错,且它更安全,更好用
System.out.println(Objects.equals(s1, s2));//false
System.out.println(Objects.isNull(s1));//true
System.out.println(Objects.isNull(s2));//false
System.out.println(Objects.nonNull(s1));//false
System.out.println(Objects.nonNull(s2));//true
}
}
六、包装类
包装类就是把基本类型的数据包装成对象
package d3_api_intger;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
Integer t2=Integer.valueOf(12);
System.out.println(t2);
//自动装箱:可以自动把基本类型的数据转换成对象。
Integer a3=12;
//自动拆箱:可以自动把包装类型的对象转换成对应的基本数据类型
int a4=a3;
// 泛型和集合不支持基本数据类型,只能支持引用数据类型。
ArrayList<Integer> list=new ArrayList<>();
list.add(12);//自动装箱
list.add(13);//自动装箱
int rs=list.get(1);//自动拆箱
}
}
6.1 包装类其他常见的操作
可以把基本类型的数据转换成字符串类型
- public static String toString(double d)
- public String toString()
可以把字符串类型的数值转换成数值本身对应的数据类型
- public static int parselnt(String s)
- public static Integer valueOf(String s)
Test.class
package d3_api_intger;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
Integer t2=Integer.valueOf(12);
System.out.println(t2);
//自动装箱:可以自动把基本类型的数据转换成对象。
Integer a3=12;
//自动拆箱:可以自动把包装类型的对象转换成对应的基本数据类型
int a4=a3;
// 泛型和集合不支持基本数据类型,只能支持引用数据类型。
ArrayList<Integer> list=new ArrayList<>();
list.add(12);//自动装箱
list.add(13);//自动装箱
int rs=list.get(1);//自动拆箱
System.out.println("================================================================================");
// 1、把基本类型的数据转换成字符串
Integer a=23;
String s=a.toString(a);
System.out.println(s+1);
// 2、把字符串类型的数值转换成对应的基本类型。
String ageStr="29";
int ageI=Integer.parseInt(ageStr);
System.out.println(ageI+1);
String scoreStr="99.5";
// double score=Double.parseDouble(scoreStr);
double score=Double.valueOf(scoreStr);
System.out.println(score+0.5);
}
}
七、StringBulider、StringBuffer
- StringBuilder代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的
- 好处:StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁。
Test1.class
package com.itheima.d4_api_stringBuilder;
public class Test {
public static void main(String[] args) {
StringBuilder s = new StringBuilder();
StringBuilder s1 = new StringBuilder("itheima");
// 1、拼接内容
s.append(12);
s.append("heima");
s.append(true);
System.out.println(s);
// 支持链式编程
s.append(666).append("hhh").append(123);
// 2、反转操作
s.reverse();
System.out.println(s);
// 3、返回字符串的长度
System.out.println(s.length());
// 4、把StringBuilder对象又转换成String类型
String rs=s.toString();
System.out.println(rs);
}
}
为啥操作字符串建议使用stringBuilder,而不用原来学过的string??
- 对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler,效率更高!
- 注意:如果操作字符串较少,或者不需要操作,以及定义字符串变量,还是建议用String
Test2.class
package com.itheima.d4_api_stringBuilder;
public class Test2 {
public static void main(String[] args) {
StringBuilder stringBuilder=new StringBuilder();
for (int i = 1; i < 1000000; i++) {
stringBuilder.append("abc");
}
System.out.println(stringBuilder);
}
}
注意:
StringBuffer的用法与StringBuilder是一模一样的,但 StringBuilder是线程不安全的 StringBuffer是线程安全的
7.1 StringBulider案例
package com.itheima.d4_api_stringBuilder;
public class Test3 {
public static void main(String[] args) {
System.out.println(getArrayData(new int[]{11, 22, 33}));
}
public static String getArrayData(int[] arr){
//1、判断arr是否为null
if(arr==null){
return null;
}
// 2、arr数组对象存在。arr=[11,22,33]
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if(i==arr.length-1){
sb.append(arr[i]);
}else {
sb.append(arr[i]).append(",");
}
}
sb.append("]");
return sb.toString();
}
}
八、StringJoiner
- JDK8开始才有的,跟StringBuilder一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。
- 好处:不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁
package com.itheima.d5_api_stringJoiner; import java.util.StringJoiner; public class Test { public static void main(String[] args) { StringJoiner stringJoiner = new StringJoiner(",", "[", "]"); stringJoiner.add("java1"); stringJoiner.add("java2"); stringJoiner.add("java3"); System.out.println(stringJoiner); System.out.println(getArrayData(new int[]{11, 22, 33})); } public static String getArrayData(int[] arr) { //1、判断arr是否为null if (arr == null) { return null; } // 2、arr数组对象存在。arr=[11,22,33] StringJoiner s = new StringJoiner(",", "[", "]"); for (int i = 0; i < arr.length; i++) { s.add(arr[i] + ""); } return s.toString(); } }
九、Math、System、Runtime
9.1 Math
代表数学,是一个工具类,里面提供的都是对数据进行操作的一些静态方法。
Test.class
package com.itheima.math;
public class Test {
public static void main(String[] args) {
// 日标:了解下Math类提供的常见方法。
// 1、public static int abs(int a):取绝对值(拿到的结果一定是正数)//public static double abs(double a)
System.out.println(Math.abs(-12));
System.out.println(Math.abs(123));
System.out.println(Math.abs(-3.14));
//2、public static double ceil(double a):向上取整
System.out.println(Math.ceil(4.0000000001));
System.out.println(Math.ceil(4.000000000));
// 3、public static double floor(double a): 向下取整
System.out.println(Math.floor(4.999999));
System.out.println(Math.floor(4.000000));
//4、public static long round(double a):四舍五入
System.out.println(Math.round(3.49999));
System.out.println(Math.round(3.5999));
//5、public static int max(int a,int b): 取较大值
// public static int min(int a,int b):取较小值
System.out.println(Math.max(10,20));
System.out.println(Math.min(10,20));
// 6、public static double pow(double a, double b):取次方
System.out.println(Math.pow(2,3));//2的三次方
// 7、public static double random():取随机数[0.0,1.0)(包前不包后)
System.out.println(Math.random());
}
}
9.2 System
System代表程序所在的系统,也是一个工具类
package com.itheima.math;
public class SystemTest {
public static void main(String[] args) {
// 目标:了解下System类的常见方法。
// 1、public static void exit(int status):
// 终止当前运行的Java虚拟机。
// 该参数用作状态代码;按照惯例,非零状态代码表示异常终止。
//System.exit(0);// 人为的终止虚拟机。(不要使用)
//2、public static long currentTimeMillis():获1取当前系统的时间
//返回的是long类型的时间毫秒值:指的是从1970-1-10:0:0开始走到此刻的总的毫秒值,1s=1000ms
long time = System.currentTimeMillis();
System.out.println(time);
for (int i = 0; i <1000000 ; i++) {
System.out.println("输出了"+i);
}
long time2=System.currentTimeMillis();
System.out.println((time2-time)/1000.0+"s");
}
}
9.3 Runtime
- 代表程序所在的运行环境。
- Runtime是一个单例类。
package com.itheima.math;
public class RunTimeTest {
public static void main(String[] args) {
//1、public static Runtime getRuntime()返回与当前Java应用程序关联的运行时对象。
Runtime r = Runtime.getRuntime();
//2、public void exit(int status)终止当前运行的虚拟机,该参数用作状态代码;按照惯例,非零状态代码表示异常终止。
// r.exit();
//3、public int availableProcessors():获取虚拟机能够使用的处理器数。
System.out.println(r.availableProcessors());
//4、public long totalMemory()返回Java虚拟机中的内存总量。
System.out.println(r.totalMemory() / 1024.0 / 1024.0 + "M");
// 5、public long freeMemory()返回Java虚拟机中的可用内存量
System.out.println(r.freeMemory() / 1024.0 / 1024.0 + "M");
// 6、public Process exec(String command)启动某个程序,并返回代表该程序的对象。
// r.exec();
//Process p=r.exec();
//Thread.sleep(5000);// 让程序在这里暂停5s后继续往下走!!
//p.destroy();// 销毁!关闭程序!
}
}
十、BigDecimal
用于解决浮点型运算时,出现结果失真的问题
package bigdecimal;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Test1 {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
// 1、把浮点型数据封装成BigDecimal对再来参与运算。
//a、public BigDecimal(double val)得到的BigDecimal对象是无法精确计算浮点型数据的。注意:不推荐使用这个
//b、public BigDecimal(String val) 得到的BigDecimal对象是可以精确计算浮点型数据的。 可以使用。
// c、public static BigDecimal value0f(double val):通过这个静态方法得到的BigDecimal对象是可以精确运算的。是最好的方案。
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
//2、public BigDecimal add(BigDecimal augend): 加法
BigDecimal c1 = a1.add(b1);
System.out.println(c1);
// 3、public BigDecimal subtract(BigDecimal augend): 減法
BigDecimal c2 = a1.subtract(b1);
System.out.println(c2);
//4、public BigDecimal multiply(BigDecimal augend): 乘法
BigDecimal c3 = a1.multiply(b1);
System.out.println(c3);
//5、public BigDecimal divide(BigDecimal b):除法
BigDecimal c4= a1.divide(b1);
System.out.println(c4);
// 6、public BiaDecimgl divide(另一个BiaDecimgl对象,精确几位,舍入模式):除法、可以设置精确几位
BigDecimal d1=BigDecimal.valueOf(0.1);
BigDecimal d2=BigDecimal.valueOf(0.3);
BigDecimal d3=d1.divide(d2,2, RoundingMode.HALF_UP);
System.out.println(d3);
// 7、public double doubleValue():把BigDecimal对象又转换成double类型的数据。
double db1=d3.doubleValue();
double db2=c1.doubleValue();
print(db1);
print(db2);
}
public static void print(double a){
System.out.println(a);
}
}
十一、JDK8之前传统的日期、时间
11.1 Date
代表的是日期和时间
package de_time;
import java.util.Date;
public class Test1Date {
// 1、创建一个Date的对象:代表系统当前时间信息的。
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
// 2、拿到时间亳秒值。
long time = d.getTime();
System.out.println(time);
// 3、把时间亳秒值转换成日期对象:2s之后的时间是多少
time += 2 * 1000;
Date d2 = new Date(time);
System.out.println(d2);
// 4、直接把日期对象的时间通过setTime方法进行修改
Date d3=new Date();
d3.setTime(time);
}
}
11.2 SimpleDateFormat
代表简单日期格式化,可以用来把日期对象、时间毫秒值格式化成我们想要的形式
package de_time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test2SimpleDateFormat {
public static void main(String[] args) throws ParseException {
// 1、准备一些时间
Date d = new Date();
System.out.println(d);
long time = d.getTime();
System.out.println(time);
// 2、格式化日期对象,和时间 毫秒值。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
String sd = simpleDateFormat.format(d);
String sd1=simpleDateFormat.format(time);
System.out.println(sd);
System.out.println("==============================================");
// 目标:掌握SimpleDateFormat解析字符串时间 成为日期对象
String dateStr="2024-6-1 16:07:11";
// 1、创建简单日期格式化对象 ,指定的时间格式必须与被解析的时间格式一模一样,否则程序会出bug.
SimpleDateFormat simpleDateFormat1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d2=simpleDateFormat1.parse(dateStr);
System.out.println(d2);
}
}
11.3 练习:秒杀活动
package de_time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test3 {
public static void main(String[] args) throws ParseException {
// 1、把开始时间、结束时间、小贾下单时间、小皮下单时间拿到程序中来
String start = "2023年11月11日 0:0:0";
String end = "2023年11月11日 0:10:0";
String xj = "2023年11月11日 0:1:18";
String xp = "2023年11月11日 0:10:57";
//2、把字符串的时间解析成日期对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date startDt = simpleDateFormat.parse(start);
Date endDt = simpleDateFormat.parse(end);
Date xjDt = simpleDateFormat.parse(xj);
Date xpDt = simpleDateFormat.parse(xp);
//3、开始判断小皮和小贾是否秒杀成功了。
//把日期对象转换成时间亳秒值来判断
long startTime = startDt.getTime();
long endTime = endDt.getTime();
long xjTime = xjDt.getTime();
long xpTime = xpDt.getTime();
if (xjTime >= startTime && xjTime <= endTime) {
System.out.println("小贾秒杀成功");
} else {
System.out.println("小贾秒杀失败");
}
if (xpTime >= startTime && xpTime <= endTime) {
System.out.println("小皮秒杀成功");
} else {
System.out.println("小皮秒杀失败");
}
}
}
11.4 Calender
代表的是系统此刻时间对应的日历,通过它可以单独获取、修改时间中的年、月、日、时、分、秒等
package de_time;
import java.util.Calendar;
import java.util.Date;
public class CalenderTest {
public static void main(String[] args) {
// 1、得到系统此刻时间对应的日历对象。
Calendar now= Calendar.getInstance();
System.out.println(now);
// 2、获取日历中的某个信息
int year=now.get(Calendar.YEAR);
System.out.println(year);
int days=now.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
// 3、拿到日历中记录的日期对象。
Date date=now.getTime();
System.out.println(date);
// 4、拿到时间毫秒值
long time=now.getTimeInMillis();
System.out.println(time);
// 5、修改日历中的某个信息
now.set(Calendar.MONTH,9);// 修改月份成为10月份。
System.out.println(now);
now.set(Calendar.DAY_OF_YEAR,125);// 修改成一年中的第125天
System.out.println(now);
// 6、为某个信息增加或者减少多少
now.add(Calendar.DAY_OF_YEAR,100);
now.add(Calendar.DAY_OF_YEAR,-10);
now.add(Calendar.DAY_OF_YEAR,6);
now.add(Calendar.HOUR,12);
System.out.println(now);
}
}
十二、JDK8开始新增的日期、时间
为什么要学JDK 8新增的时间?
1、设计不合理,使用不方便,很多都被淘汰了。
2、都是可变对象,修改后会丢失最开始的时间信息。
3、线程不安全。
4、只能精确到毫秒。
JDK8开始之后新增的时间API
1、设计更合理,功能丰富,使用更方便。
2、都是不可变对象,修改后会返回新的时间对象,不会丢失最开始的时间。
3、线程安全。
4、能精确到毫秒、纳秒。
package jdk8_time;
import java.util.Calendar;
import java.util.Date;
public class Test {
public static void main(String[] args) {
// 传统的时间类(Date、SimpleDateFormat、Calendar)存在如下问题:
// 1、设计不合理,使用不方便,很多都被淘汰了。
Date d = new Date();
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
System.out.println(year);
// 2、都是可变对象,修改后会丢失最开始的时间信息。
// 3、线程不安全。
// 4、不能精确到纳秒,只能精确到亳秒。
//1秒= 1000毫秒
// 1毫秒=1000微秒
// 1微妙= 1000纳秒
}
}
12.1 LocalDate、LocalTime、LocalDateTime
- LocalDate:代表本地日期(年、月、日、星期)
- LocalTime:代表本地时间(时、分、秒、纳秒)
- LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)
-
package jdk8_time; import java.time.LocalDate; public class Test1 { public static void main(String[] args) { //0、获取本地日期对象(不可变对象) LocalDate ld = LocalDate.now();//年月日 System.out.println(ld); // 1、获取日期对象中的信息 int year = ld.getYear();//年 int month = ld.getMonthValue();//月(1-12) int day = ld.getDayOfMonth();//日 int dayOfYear = ld.getDayOfYear(); // 一年中的第几天 int day0fWeek = ld.getDayOfWeek().getValue();// 星期几 System.out.println(year); // 2、直接修改某个信息:withYear、withMonth、withDayOfMonth、withDayOfYear LocalDate ld2=ld.withYear(2099); LocalDate ld3=ld.withMonth(12); System.out.println(ld2); System.out.println(ld3); System.out.println(ld); //3、把某个信息加多少:plusYears、plusMonths、plusDays、plusWeeks LocalDate ld4=ld.plusYears(2); LocalDate ld5=ld.plusMonths(2); System.out.println(ld4); System.out.println(ld5); // 4、把某个信息减多少:minusYears、minusMonths、minusDays、minusWeeks LocalDate ld6=ld.minusYears(2); LocalDate ld7=ld.minusMonths(2); System.out.println(ld4); System.out.println(ld5); //5、获取指定目期的LocalDate对象: public static LocalDate of(int year,int month) LocalDate ld8=LocalDate.of(2099,12,12); LocalDate ld9=LocalDate.of(2099,12,12); // 6、判断2个日期对象,是否相等,在前还是在后:equals isBefore isAfter System.out.println(ld8.equals(ld9));//true System.out.println(ld8.isAfter(ld));//true System.out.println(ld8.isBefore(ld));//false //7、可以把LocalDateTime转换成LocalDate和LocalTime // public LocalDate toLocalDate() // public LocalTime toLocalTime() // public static LocalDateTime of(LocalDate date, LocalTime time)LocalDate ld = ldt.toLocalDate() } }
12. 2 ZoneId:时区、ZonedDateTime:带时区的时间
Zoneld:代表时区ld
package jdk8_time;
import java.time.Clock;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Test4_Zoneld_ZoneDateTime {
public static void main(String[] args) {
///1、ZoneId的常见方法
// 获取系统默认的时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId.getId());
System.out.println(zoneId);
//public static Set<String>getAvailableZoneIds(): 获取Java支持的全部时区Id
System.out.println(ZoneId.getAvailableZoneIds());
// public static ZoneId of(String zoneId):把某个时区id封装成ZoneId对象
ZoneId zoneId1 = ZoneId.of("America/Marigot");
//2、ZonedDateTime:带时区的时间。
// public static ZonedDateTime now(ZoneId zone): 获取某个时区的ZonedDateTime对象。
ZonedDateTime now = ZonedDateTime.now(zoneId1);
System.out.println(now);
// 世界标准时间了
ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC());
System.out.println(now1);
// public static ZonedDateTime now():获取系统默认时区的ZonedDateTime对象
ZonedDateTime now2 = ZonedDateTime.now();
System.out.println(now2);
// Calendar instance=Calendar.getInstance(TimeZone.getTimeZone(zoneId1));
}
}
12.3 instant:时间线上的某个时刻/时间戳
通过获取Instant的对象可以拿到此刻的时间,该时间由两部分组成:从1970-01-0100:00:00 开始走到此刻的总秒数+不够1秒的纳秒数
- 作用:可以用来记录代码的执行时间,或用于记录用户操作某个事件的时间点。
- 传统的Date类,只能精确到毫秒,并且是可变对象;
- 新增的Instant类,可以精确到纳秒,并且是不可变对象,推荐用Instant代替Date。
package jdk8_time;
import java.time.Instant;
public class Test5_Instant {
public static void main(String[] args) {
//1、创建Instant的对象,获取此刻时间信息
Instant now = Instant.now();
// 2、获取总秒数
long second = now.getEpochSecond();
System.out.println(second);
//3、不够1秒的纳秒数
int nano = now.getNano();
System.out.println(nano);
System.out.println(now);
Instant instant= now.plusNanos(111);
//Instant对象的作用:做代码的性能分析,或者记录用户的操作时间点
Instant now1=Instant.now();
//代码执行
Instant now2=Instant.now();
}
}
12.4 DateTimeFormatter(线程安全):格式化器,用于时间的格式化、解析
package jdk8_time;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Test6_DateTimeFormatter {
public static void main(String[] args) {
//1、创建一个日期时间格式化器对象出来。
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
//2、对时间进行格式化
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
System.out.println(dateTimeFormatter.format(now));
//3、格式化时间,其实还有一种方案。
String rs=now.format(dateTimeFormatter);// 反向格式化
System.out.println(rs);
//4、解析时间:解析时间一般使用LocalDateTime提供的解析方法来解析
String dateStr="2029年12月12日 12:12:11";
LocalDateTime ldt=LocalDateTime.parse(dateStr,dateTimeFormatter);
System.out.println(ldt);
}
}
12.5 Period:计算日期间隔(年,月,日)、Duration:计算时间间隔(时、分、秒,纳秒)
(1)period
可以用于计算两个 LocalDate对象 相差的年数、月数、天数。
package jdk8_time;
import java.time.LocalDate;
import java.time.Period;
public class Test8_Duration {
public static void main(String[] args) {
// 1、创建Period对象,封装两个日期对象。
LocalDate start= LocalDate.of(2020,1,1);
LocalDate end= LocalDate.of(2024,6,1);
// 1、创建Period对象,封装两个日期对象。
Period period=Period.between(start,end);
System.out.println(period);
//2、通过period对象获取两个日期对象相差的信息
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
}
}
(2) Duration
可以用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数;支持LocalTime、、LocalDateTime、Instant等时间。
package jdk8_time;
import java.time.Duration;
import java.time.LocalDateTime;
public class Test8_Duration {
public static void main(String[] args) {
//1、得到Duration对象
LocalDateTime start = LocalDateTime.of(2020, 11, 11, 11, 10, 10);
LocalDateTime end = LocalDateTime.of(2020, 11, 11, 11, 11, 11);
Duration duration = Duration.between(start,end);
//2、获取两个时间对象间隔的信息
System.out.println(duration.toDays());//间隔多少天
System.out.println(duration.toHours());//间隔多少小时
System.out.println(duration.toMinutes());//间隔多少分钟
System.out.println(duration.toSeconds());//间隔多少秒
System.out.println(duration.toMillis());//间隔多少毫秒
System.out.println(duration.toNanos());//价格多少纳秒
}
}
1、 Period有啥作用?
- 可以用于计算两个 LocalDate对象 相差的年数、月数、天数。
2、 Duration有啥作用?
- 可以用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数,支持LocalTime、LocalDateTime、Instant等时间
十三、Arrays
用来操作数组的一个工具类
package com.itheima.Arrays;
import java.util.Arrays;
import java.util.function.IntToDoubleFunction;
public class ArraysTest {
public static void main(String[] args) {
//1、public static toString类型[]arr):返回数组的内容
int[] arr = {10, 20, 30, 40, 50, 60};
System.out.println(Arrays.toString(arr));
// 2、public static 类型[] copyOfRange(类型[〕arr,起始索引,结束索引):拷贝数组(指定范围,包前不包后)
int []arr2=Arrays.copyOfRange(arr,1,4);
System.out.println(Arrays.toString(arr2));
//3、public static copyOf(类型[]arr,int newLength):拷贝数组,可以指定新数组的长度。
int arr3[]=Arrays.copyOf(arr,10);//长的后面为0,短的长度不够有多少copy多少
System.out.println(Arrays.toString(arr3));
// 4、public static setAll(double[l array, IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去。
double[] prices={99.8,128,100};
//把所有的价格都打八折,然后又存进去
Arrays.setAll(prices, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {
//value=0 1 2
return prices[value]*0.8;
}
});
System.out.println(Arrays.toString(prices));
//5、public static void sort(类型[]arr):对数组进行排序(默认是升序排序)
Arrays.sort(prices);
System.out.println(Arrays.toString(prices));
}
}
13.1 对数组中的数据进行排序
方式一:让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。
Student.class
package com.itheima.Arrays;
public class Student implements Comparable<Student> {
private String name;
private double height;
private int age;
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}
@Override
// 约定1:认为左边对象大于右边对象 请您返回正整数
// 约定2:认为左边对象小于 右边对象请您返回负整数
// 约定:认为左边对象 等于 右边对象 请您一定返回0
//按照年龄升序排序。
public int compareTo(Student o) {
/* if (this.age > o.age) {
return 1;
} else if(this.age < o.age) {
return -1;
}*/
// return this.age - o.age;//升序
return o.age - this.age;//降序
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", height=" + height +
", age=" + age +
'}';
}
}
Test.class
package com.itheima.Arrays;
import java.util.Arrays;
public class ArraysTest2 {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 169.5, 23);
students[1] = new Student("李四", 163.8, 26);
students[2] = new Student("王五", 163.8, 26);
students[3] = new Student("赵六", 167.5, 24);
//1、public static void sort(类型[]arr):对数组进行排序。
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}
方式二:使用下面这个sort方法,创建comparator比较器接口的匿名内部类对象,然后自己制定比较规则。
- public static <T> void sort(T] arr,Comparator<?superT>c)对数组进行排序(支持自定义排序规则)
Test.class
package com.itheima.Arrays;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysTest2 {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 169.5, 23);
students[1] = new Student("李四", 163.8, 26);
students[2] = new Student("王五", 163.8, 26);
students[3] = new Student("赵六", 167.5, 24);
//1、public static void sort(类型[]arr):对数组进行排序。
Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 2、public static <T>void sort(T[] arr, Comparator<? super T> c)
// 参数一:需要排序的数维
// 参数二:Comparator比较器对象(用来制定对象的比较规则)
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 制定比较规则了:左边对象 01右边对象 02
// 约定1:认为左边对象大于右边对象 请您返回正整数
// 约定2:认为左边对象小于右边对象 请您返回负整数
// 约定3:认为左边对象等于右边对象 请您一定返回0
/* if(o1.getHeight()>o2.getHeight()){
return 1;
}else if(o1.getHeight()<o2.getHeight()){
return -1;
}
return 0;*/
// return Double.compare(o1.getHeight(),o2.getHeight());//升序
return Double.compare(o2.getHeight(),o1.getHeight());//降序
}
});
}
}
十四、JDK8新特性:Lambda表达式
14.1 认识Lambda表达式
Lambda表达式是JDK 8开始新增的一种语法形式;作用:用于化名内部类的代码写法
注意:Lambda表达式只能简化函数式接口的匿名内部类!!!
什么是函数式接口?
- 有且仅有一个抽象方法的接口。
- 注意:将来我们见到的大部分函数式接口,上面都可能会有一个@Functionalinterface的注解,有该注解的接口就必定是函数式接口
LambdaTest.class
package lambda;
public class LambdaTest {
public static void main(String[] args) {
/* Animal a= new Animal() {
@Override
public void run() {
System.out.println("狗跑的快");
}
};
a.run();*/
// 注意:Lambda表达式并不是说能简化全部匿名内部类的写法,只能简化函数式接口的匿名内部类。
/* Animal a=()->{
System.out.println("狗跑的快");
};
a.run();*/
/* Swimming s = new Swimming() {
@Override
public void swim() {
System.out.println("学生快乐的游泳");
}
};*/
Swimming s = () -> {
System.out.println("学生快乐的游泳");
};
s.swim();
}
}
abstract class Animal {
public abstract void run();
}
interface Swimming {
void swim();
}
14.2 Lambda表达式的省略规则
- 参数类型可以省略不写
- 如果只有一个参数,参数类型可以省略,同时()也可以省略。
- 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如果这行代码是return语句,也必须去掉return不写。
LambdaTest2.class
package lambda;
import com.itheima.Arrays.Student;
import java.util.Arrays;
public class LambdaTest2 {
public static void main(String[] args) {
// 目标:使用Lambda简化函数式接口。
double[] prices ={99.8,128,100};
//第一种:
// Arrays.setAll(prices, new IntToDoubleFunction() {
// @Override
// public double applyAsDouble(int value) {
// return prices[value]*0.8;
// }
// });
//第二种简化:
// Arrays.setAll(prices, value -> {
// return prices[value]*0.8;
// });
//第三种简化:
// Arrays.setAll(prices, value -> prices[value]*0.8);
System.out.println(Arrays.toString(prices));
System.out.println("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
Student[] students = new Student[4];
students[0] = new Student("张三", 169.5, 23);
students[1] = new Student("李四", 163.8, 26);
students[2] = new Student("王五", 163.8, 26);
students[3] = new Student("赵六", 167.5, 24);
//第一种
// Arrays.sort(students, new Comparator<Student>() {
// @Override
// public int compare(Student o1, Student o2) {
// return Double.compare(o1.getHeight(), o2.getHeight());
// }
// });
//第二种
// Arrays.sort(students,(o1,o2)->{
// return Double.compare(o1.getHeight(), o2.getHeight());
// });
//第三种
Arrays.sort(students,(o1,o2)->Double.compare(o1.getHeight(), o2.getHeight()));
System.out.println(Arrays.toString(students));
}
}
十五、JDK8新特性:方法引用
15.1 静态方法的引用
- 类名::静态方法
使用场景
- 如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。
新建一个ComparaData.class
package method_reference;
import com.itheima.Arrays.Student;
public class CompareData {
static int compareByAge(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
Test.class
package method_reference;
import com.itheima.Arrays.Student;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 169.5, 23);
students[1] = new Student("李四", 163.8, 26);
students[2] = new Student("王五", 163.8, 26);
students[3] = new Student("赵六", 167.5, 24);
//升序
Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
//进一步简化,使用静态方法调用
Arrays.sort(students, CompareData::compareByAge);
System.out.println(Arrays.toString(students));
}
}
15.2 实例方法的引用
- 对象名::实例方法
使用场景
- 如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用
package method_reference;
import com.itheima.Arrays.Student;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 169.5, 23);
students[1] = new Student("李四", 163.8, 26);
students[2] = new Student("王五", 163.8, 26);
students[3] = new Student("赵六", 167.5, 24);
//升序
Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
//进一步简化,使用静态方法调用
Arrays.sort(students, CompareData::compareByAge);
System.out.println(Arrays.toString(students));
CompareData compareData=new CompareData();
//Arrays.sort(students,(o1,o2)->compareData.compareByAgeDesc(o1,o2));
//使用实例方法引用
Arrays.sort(students,compareData::compareByAgeDesc);
System.out.println(Arrays.toString(students));
}
}
15.3 特定类型的方法引用
- 类型::方法。
使用场景
- 如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用
Test.class
package method_reference;
import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
//帮我生成一组英文字符串数组,数组内容有8个英文名
String[] names = {"Tom","Jerry","Mike","Tony","Jim","James","Jimmy","Jenny"};
//要求忽略首字符大小写进行排序
// Arrays.sort(names, new Comparator<String>() {
// @Override
// public int compare(String o1, String o2) {
// // 制定比较规则
// return o1.compareToIgnoreCase(o2);
// }
// });
//Arrays.sort(names,(o1,o2)->o1.compareToIgnoreCase(o2));
//特定方法引用
Arrays.sort(names,String::compareToIgnoreCase);
System.out.println(Arrays.toString(names));
}
}
15.4 构造器引用
- 类名::new
使用场景
- 如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用
创建一个Car.class
package method_reference;
public class Car {
private String name;
private double price;
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 Car() {
}
public Car(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
Test.class
package method_reference;
public class Test3 {
public static void main(String[] args) {
// 1、创建这个接口的匿卫内部类对象。
// CreateCar cc=new CreateCar() {
// @Override
// public Car create(String name, double price) {
// return new Car(name, price);
// }
// };
//简化
// CreateCar cc = (name, price) -> new Car(name, price);
//第二次简化,构造器引用
CreateCar cc= Car::new;
Car c = cc.create("奔驰", 100.2);
System.out.println(c);
}
}
interface CreateCar {
Car create(String name, double price);
}
十六、常见算法
16.1 冒泡排序
package algorithm;
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) {
// 1、准备一个数组
int[] arr = {4, 2, 3, 1};
//定义一个循环控制排几轮
for (int i = 0; i < arr.length - 1; i++) {
// i=0 1 2 [4,2,3,1] 次数
// i=0 第一轮 0 1 2 3
// i=1 第二轮 0 1 2
// i=2 第三轮 0
// 3、定义一个循环控制每轮比较几次。
for (int j = 0; j < arr.length - i - 1; j++) {
// 判断当前位置的元素值,是否大于后一个位置处的元素值,如果大则交换。
if(arr[j]>arr[j+1]){
int temp = arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
}
System.out.println(Arrays.toString(arr));
}
}
}
}
16.2 选择排序
每轮选择当前位置,开始找出后面的较小值与该位置交换
package algorithm;
import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
//方式一:
//1. 准备好一个数组
int[] arr = {4, 1, 3, 2};
// 0 1 2 3
// //2. 控制选几轮
// for (int i = 0; i < arr.length - 1; i++) {
// //i=0 第一轮 j=1 2 3
// //i=1 第二轮 j=2 3
// //i=2 第三轮 j=3
// //3. 控制每轮选择几次
// 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));
// }
//方式二
//2. 控制选几轮
for (int i = 0; i < arr.length - 1; i++) {
//i=0 第一轮 j=1 2 3
//i=1 第二轮 j=2 3
//i=2 第三轮 j=3
//3. 控制每轮选择几次
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
// 判断当前位置是否大于后面位置处的元素值,若大于则交换。
if (arr[minIndex] > arr[j]) {
minIndex = j;
}
//决定是否交换
if(i!=minIndex){
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
System.out.println(Arrays.toString(arr));
}
}
}
16.3 二分查找
前提条件:数组中的数据必须是有序的
核心思想:每次排除一半的数据,查询数据的性能明显提高极多!
结论:二分查找正常的折半条件应该是开始位置left<=结束位置right
package algorithm;
public class Test3 {
public static void main(String[] args) {
//准备好一个静态数组,长度为10,并在数组里填写好数字
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
System.out.println(binarySearch(arr, 6));
}
public static int binarySearch(int[] arr, int data) {
// 1. 定义两个变量,一个站在左边的位置,一个站在右边的位置
int left = 0;
int right = arr.length - 1;
//2. 定义一个循环控制折半
while (left < right) {
//3. 每次折半,都算出中间位置的索引
int middle = (left + right) / 2;
//4. 判断当前要找的元素,与中间位置处的元素值的大小情况
if (data < arr[middle]) {
//往左边找,戒指位置(右边位置)=中间位置-1
right = middle - 1;
} else if (data > arr[middle]) {
//往右边周,起始位置(左右位置)=中间位置+1
left = middle + 1;
} else {
//中间位置的元素值,正好等于我们要找的元素值
return middle;
}
}
return -1;//-1 特殊结果,就代表没有要找的数据! 数组中不存在该数据
}
}
十七、正则表达式
就是由一些特定的字符组成,代表的是一个规则。
作用一:用来校验数据格式是否合法
作用二:在一段文本中查找满足要求的内容
public class regex {
// 需求:校验QQ号码是否正确,要求全部是数字,长度是(6-20)之间,不能以0开头。
public static void main(String[] args) {
System.out.println(checkQQ(null));
System.out.println(checkQQ("2123243342342342131f23123123123123"));
System.out.println(checkQQ("0912321"));
System.out.println(checkQQ("2435241061"));
System.out.println("================================================================================================================================================================================");
System.out.println(checkQQ1(null));
System.out.println(checkQQ1("2123243342342342131f23123123123123"));
System.out.println(checkQQ1("0912321"));
System.out.println(checkQQ1("2435241061"));
}
public static boolean checkQQ1(String qq) {
return qq != null && qq.matches("[1-9]\\d{5,19}");
}
public static boolean checkQQ(String qq) {
// 1.判断qq号码是否为null
if (qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20) {
return false;
}
//2. qq至少是不是null,不是以0开头,满足6-20之间的长度
//判断qq号码中事发后是数字
//假如qq=324gj345
for (int i = 0; i < qq.length(); i++) {
//根据索引提取当前位置处的字符
char ch = qq.charAt(i);
//判断ch记住的字符,如果不是数字,qq号码不合法
if (ch < '0' || ch > '9') {
return false;
}
}
//3.说明qq号码合法
return true;
}
}
17.1 书写规则
判断字符串是否匹配正则表达式,匹配返回true,不匹配返回false。public boolean matches(string regex)
package regex;
public class RegexTest1 {
public static void main(String[] args) {
System.out.println("a".matches("[abc]")); //[abc]只能匹配a、b、c
System.out.println("d".matches("[abcd]"));
System.out.println("d".matches("[^abc]"));//[^abc] 不能是abc
System.out.println(("9".matches("[^abc]")));
System.out.println("b".matches("[a-zA-Z]"));//[a-zA-Z] 只能是a-z A-Z的字符
System.out.println("2".matches("[a-zA-Z]"));
System.out.println("k".matches("[a-z&&[^bc]]"));//:a到z,除了b和c
System.out.println("b".matches("[a-z&&[^bc]]"));
System.out.println("ab".matches("[a-zA-Z0-9]"));// false 注意:以上带[内容]的规则都只能用于匹配单个字符
// 2、预定义字符(只能匹配单个字符) \d \D \s \S \w \W
System.out.println("哈".matches( "."));//.可以匹配任意字符
System.out.println("哈".matches( "."));
System.out.println("3".matches( "\\d"));//\d:0-9
System.out.println("a".matches("\\d"));
System.out.println("".matches( "\\s")); //\s:代表一个空白字符
System.out.println("a".matches("\\s"));// false
System.out.println("a".matches("\\w"));//\w:[a-zA-Z_0-9]\
System.out.println("I".matches( "\\w"));
System.out.println("哈".matches( "\\w"));
System.out.println("哈".matches( "\\W")); //[^\w]不能是a-zA-Z_0-9
System.out.println("a".matches( "\\W"));
System.out.println("23232".matches("\\d"));//false 注意:以上预定义字符都只能匹配单个字符。
// 3、数量词:? * + {n} {n,} {n,m}
System.out.println("a".matches("\\w?"));//?代表0次或1次
System.out.println("".matches( "\\w?"));
System.out.println("abc".matches( "\\w?"));
System.out.println("abc12".matches("\\w*"));//*代表日次或多次
System.out.println("".matches( "\\w*"));
System.out.println("abc12张".matches( "\\w*"));
System.out.println("abc12".matches( "\\w+"));//+代表1次或多次
System.out.println("".matches( "\\w+"));
System.out.println("abc12张".matches( "\\w+"));//+ 代表1次或多次
}
}
17.2 应用案例
package regex;
import java.util.Scanner;
public class RegexTest3 {
public static void main(String[] args) {
//checkPhone();
checkEmail();
}
public static void checkPhone() {
while (true) {
System.out.println("请您输入您的电话号码(手机|座机):");
Scanner sc = new Scanner(System.in);
String phone = sc.nextLine();
if (phone.matches("1[3-9]\\d{9}|(0\\d{2,7}-?[1-9]\\d{4,19})")) {
System.out.println("恭喜您输入正确");
} else {
System.out.println("输入错误");
}
}
}
public static void checkEmail() {
while (true) {
System.out.println("请您输入您的邮箱:");
Scanner sc = new Scanner(System.in);
String email = sc.nextLine();
if (email.matches("\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}")) {
System.out.println("恭喜您输入正确");
} else {
System.out.println("输入错误");
}
}
}
}
17.3 爬取信息
package regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest4 {
public static void main(String[] args) {
method1();
}
// 需求1:从以下内容中爬取出,手机,邮箱,座机、400电话等信息。
public static void method1() {
String data = "来学习Java,\n" +
"电话:1866668888,18699997777\n" +
"或者联系邮箱:boniuGitcast.cn,\n" +
"座机电话:01036517895,010-98951256\n" +
"邮箱:bozai@itcast.cn,\n" +
"邮箱:dlei0009@163.com,\n" +
"热线电话:400-618-909日,400-618-400日,400618400日,400618909日";
//1.定义爬取规则
String regex = "(1[3-9]\\d{9}|(0\\d{2,7}-?[1-9]\\d{4,19})|\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})" +
"|400-?\\d{3,7}-?\\d{3,7}";
//2、把正则表达式封装成一个Pattern对象
Pattern pattern = Pattern.compile(regex);
//3.通过pattern对象去获取查找内容的匹配器对象
Matcher matcher = pattern.matcher(data);
// 4、定义一个循环开始爬取信息
while (matcher.find()) {
String rs = matcher.group();//获取找到后的内容
System.out.println(rs);
}
}
}
17.4 用于搜索替换、分割内容
package regex;
import java.util.Arrays;
public class RegexTest5 {
public static void main(String[] args) {
//1、public String replaceAll(String regex,String newstr):按照正则表达式匹配的内容进行替换
//需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中间的非中文字符替换成"_"
String s = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
System.out.println(s.replaceAll("\\w+", "-"));
//需求2(拓展):某语音系统,收到一个口吃的人说的“我我我喜欢编编编编编编编编编编编编程程程!",需要优化成"我喜欢编程!"
//(.)一组:.匹配任意字符的。
//\\1:为这个组声明一个组号:1号
//+:声明必须是重复的字
//$1可以去取到第1组代表的那个重复的字
String s1 = "我我我喜欢编编编编编编编编编编编编程程程!";
System.out.println(s1.replaceAll("(.)\\1+", "$1"));
//2、public string[] split(string regex):按照正则表达式匹配的内容进行分制字符串,反回一个字符串数组。
//需求1:请把古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中的人名获取出来。
String s2="古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
String []name=s2.split("\\w+");
System.out.println(Arrays.toString(name));
}
}
十八、异常
18.1 异常概述
异常就是代表程序出现的问题
- Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来说白了,Error是给sun公司自己用的,不是给我们程序员用的,因此我们开发人员不用管它。
- Exception:叫异常,它代表的才是我们程序可能出现的问题,所以,我们程序员通常会用Exception以及它的孩子来封装程序出现的问
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)
- 编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)
18.2 自定义异常
1.自定义运行异常
AgeIllegalRuntimeException.class
package exception;
// 1、必须让这个类继承自RuntimeException,才能成为一个运行时异常类。
public class AgeIllegalRuntimeException extends RuntimeException {
public AgeIllegalRuntimeException(String message) {
super(message);
}
}
2.自定义编译异常
AgeIllegalException.class
package exception;
public class AgeIllegalException extends Exception {
public AgeIllegalException(String message) {
super(message);
}
}
ExceptionTest.class
package exception;
public class ExceptionTest2 {
public static void main(String[] args) {
// 需求:保存一个合法的年龄
try {
saveAge(232);
System.out.println("保存年龄成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("保存年龄失败!");
}
System.out.println("===================================================================");
try {
saveAge2(23);
System.out.println("保存年龄成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("保存年龄失败!");
}
}
public static void saveAge2(int age) throws AgeIllegalException{
if(age>0&&age<150){
System.out.println("年龄保存成功!"+age);
}else {
//用一个对象封装这个问题
// 用一个异常对象封装这个问题
// throw 抛出去这个异常对象
// throws 用在方法上,抛出方法内部的异常
throw new AgeIllegalException("年龄不合法!");
}
}
public static void saveAge(int age){
if(age>0&&age<150){
System.out.println("年龄保存成功!"+age);
}else {
//用一个对象封装这个问题
//throw 抛出这个问题
throw new AgeIllegalRuntimeException("年龄不合法!");
}
}
}
18.3 异常的处理
一般来说在try catch 的时候和throws抛出异常的时候直接可以使用Exception就可以
1.捕获异常,记录异常并响应合适的信息给用户
package exception;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionTest3 {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
System.out.println("您输入的信息有问题!");
}
}
public static void test1() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse("2024-6-1 11:24:11");
System.out.println(date);
test2();
}
public static void test2() throws Exception {
//读取文件
InputStream is = new FileInputStream("D:/meiwwww.text");
}
}
2.捕获异常,尝试重新修复
package exception;
import java.util.Scanner;
public class ExceptionTest4 {
public static void main(String[] args) {
// 需求:调用一个方法,让用户输入一个合适的价格返回为止
// 尝试修复
while (true) {
try {
System.out.println(getMoney());
} catch (Exception e) {
System.out.println("请您输入合法的数字");
}
}
}
public static double getMoney() {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请您输入合适的价格:");
double money = sc.nextDouble();
if (money >= 0) {
return money;
} else {
System.out.println("您输入的价格是不合适的!");
}
}
}
}