18Java基础之API(二)
arrays
- 用于操作数组的一个工具类。
![image]()
如果数组中存储的是对象,如何排序?
- 让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。
- 使用下面sort方法,创建comparator比较器接口的匿名内部类对象,然后自己制定比较规则。
public staticvoid sort(T[] arr, Comparator<?super T> c) 对数组进行排序(支持自定义排序规则)
3.compareTo()方法中,JAVA官方规定:
- 如果认为左边大于右边,请返回正整数;
- 如果认为左边小于右边,请返回负整数;
- 如果认为左边等于右边,请返回0;
- 这么干,默认就是升序排列;
案例:
学生类:
package com.javabase.d1_arrays;
public class Student implements Comparable<Student>{
private String name;
private int age;
private char gender;
private double height;
public Student() {
}
public Student(String name, int age, char gender, double height) {
this.name = name;
this.age = age;
this.gender = gender;
this.height = height;
}
// 自定义排序规则方式一:让对象所在的类实现比较规则接口Comparable,重写CompareTo方法,来指定比较规则。
// 指定大小规则
// 比较者:this
// 被比较者:o
@Override
public int compareTo(Student o) {
/*
* 官方定制规则:
* 如果认为左边大于右边,请返回正整数
* 如果认为左边小于右边,请返回负整数
* 如果认为左边等于右边,请返回0
* 只有这么干,默认就是升序排列
* */
// if(this.age > o.age) return 1;
// else if(this.age < o.age) return -1;
//
// return 0;
return this.age -o.age; // 年龄升序
return o.age - this.age;// 年龄降序
}
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 char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", height=" + height +
'}'+ "\n";
}
}
测试:
//目标:给存储对象的数组进行排序
public class ArraysDemo02 {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 18, '男', 1.88);
students[1] = new Student("李四", 19, '女', 1.68);
students[2] = new Student("王五", 20, '男', 1.78);
students[3] = new Student("赵六", 21, '女', 1.98);
Arrays.sort(students);// 报错
System.out.println(Arrays.toString(students));
System.out.println("-----------------------------");
// 自定义排序规则方式二:sort存在重载的方法,支持自带Comparator比较器对象来直接指定比较规则(优先使用,就近原则)
// public static <T> void sort(T[] a, Comparator<? super T> c)
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();
return Double.compare(o1.getHeight(), o2.getHeight());
}
});
}
}
**注意:**自定义排序二中,对象比较时,如果是整型,则可以直接减,然后返回结果。如果是double类型,则需要调用Double.compare()方法来进行比较,然后将结果返回。
Lambda表达式
- Lambda表达式是JDK8开始新增的一种语法形式;
- 作用:用于简化匿名内部类的代码写法。
- 格式:
(被重写方法的形参列表)->{
被重写方法的方法体代码;
}
注意:Lambda表达式只能简化函数式接口的匿名内部类!!!
什么是函数式接口?
- 有且仅有一个抽象方法的接口。
- 注意:以后我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,有该注解的接口就必定是函数式接口。
案例:
// 目标:认识Lambda是如何简化匿名内部类的
public class Test01 {
public static void main(String[] args) {
Animal a1 = new Animal() {
@Override
public void run() {
System.out.println("老虎跑的贼快!");
}
};
a1.run();
// 错误示范:Lambda并不能简化所有匿名内部类的代码。只能简化函数式接口的匿名内部类。
// Animal a2 = () ->{
// System.out.println("老虎跑的贼快!");
// };
// a2.run();
//Lambda可以简化函数式接口的匿名内部类
// 之所以可以简化代码,是因为它可以通过上下文推断出真实的代码形式;
Swiming s1 = () ->{
System.out.println("我游泳速度贼快!");
};
s1.swim();
}
}
@FunctionalInterface //函数式接口,有且只有一个抽象方法
interface Swiming{
void swim();
}
abstract class Animal{
public abstract void run();
}
案例:lambda表达式简化的例子
import java.util.Arrays;
import java.util.Comparator;
import java.util.function.IntToDoubleFunction;
//目标:掌握Lambda表达式简化常见函数式接口的匿名内部类
public class Test02 {
public static void main(String[] args) {
double[] scores = {95.5, 86.1, 55.6, 86,96,88.2};
/* Arrays.setAll(scores, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int index) {
return scores[index] + 10;
}
});*/
Arrays.setAll(scores, (int index) ->{
return scores[index] + 10;
});
System.out.println(Arrays.toString(scores));
System.out.println("-----------------------------");
Student[] students = new Student[4];
students[0] = new Student("张三", 18, '男', 1.88);
students[1] = new Student("李四", 19, '女', 1.68);
students[2] = new Student("王五", 20, '男', 1.78);
students[3] = new Student("赵六", 21, '女', 1.98);
System.out.println(Arrays.toString(students));
System.out.println("-----------------------------");
/*Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();
return Double.compare(o1.getHeight(), o2.getHeight());
}
});*/
Arrays.sort(students,(Student o1, Student o2) ->{
// return o1.getAge() - o2.getAge();
return Double.compare(o1.getHeight(), o2.getHeight());
});
}
}
Lambda表达式的省略写法(进一步简化Lambda表达式的写法)
- 参数类型可以省略不写
- 如果只有一个参数,参数类型可以省略,同时()也可以省略
- 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号。此时,如果这行代码是return语句,也必须去掉return不写。
案例:
public class Test02 {
public static void main(String[] args) {
double[] scores = {95.5, 86.1, 55.6, 86,96,88.2};
/* Arrays.setAll(scores, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int index) {
return scores[index] + 10;
}
});*/
Arrays.setAll(scores, (int index) ->{
return scores[index] + 10;
});
System.out.println(Arrays.toString(scores));
System.out.println("-----------------------------");
Student[] students = new Student[4];
students[0] = new Student("张三", 18, '男', 1.88);
students[1] = new Student("李四", 19, '女', 1.68);
students[2] = new Student("王五", 20, '男', 1.78);
students[3] = new Student("赵六", 21, '女', 1.98);
// Lambda规则
//1. 参数类型可以不写
Arrays.setAll(scores, (index) ->{
return scores[index] + 10;
});
Arrays.sort(students,(o1, o2) ->{
// return o1.getAge() - o2.getAge();
return Double.compare(o1.getHeight(), o2.getHeight());
});
//2. 如果只有一个参数,参数类型可以省略,同时()也可以省略
Arrays.setAll(scores, index ->{
return scores[index] + 10;
});
//3. 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号。
// 此时,如果这行代码是return语句,也必须去掉return不写
Arrays.sort(students,(o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight()));
// return o1.getAge() - o2.getAge();
Arrays.setAll(scores, index -> scores[index] + 10);
}
}
JDK8新特性:方法引用
- 静态方法的引用
- 类名::静态方法。
使用场景
- 如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用了。
案例:
学生类:(沿用之前创建的学生类,只是新增了方法)
public static int compareByHeight(Student o1, Student o2){
return Double.compare(o1.getHeight(), o2.getHeight());
}
测试方法:
public class Test03 {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 18, '男', 1.88);
students[1] = new Student("李四", 19, '女', 1.68);
students[2] = new Student("王五", 20, '男', 1.78);
students[3] = new Student("赵六", 21, '女', 1.98);
// Arrays.sort(students,(o1, o2) -> Student.compareByHeight(o1, o2));
Arrays.sort(students,Student::compareByHeight);//终极写法:静态引用
System.out.println(Arrays.toString(students));
}
}
实例方法引用
- 对象名::实例方法
使用场景
- 如果某个Lambda表达式里只有调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用了。
案例:
public class Test04 {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new Student("张三", 18, '男', 1.88);
students[1] = new Student("李四", 19, '女', 1.68);
students[2] = new Student("王五", 20, '男', 1.78);
students[3] = new Student("赵六", 21, '女', 1.98);
// Arrays.sort(students,(o1,o2)-> Double.compare(o1.getHeight(),o2.getHeight()));
Test04 t = new Test04();
Arrays.sort(students,t::compare);
}
public int compare(Student o1, Student o2){
return Double.compare(o1.getHeight(),o2.getHeight());
}
}
特定类型方法的引用
- 类型::方法
使用场景
- 如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
案例:
//目标:特定类型的方法引用
public class Test05 {
public static void main(String[] args) {
String[] names = {"dlei", "Angela", "baby", "caocao", "Coach", "曹操", "deby", "eason", "andy"};
//对它们进行排序,按照首字母编号排序
Arrays.sort(names);
System.out.println(Arrays.toString(names));
/* 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);
}
}
构造器引用
- 类名::new
使用场景
- 如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。
案例:
//目标:掌握构造器引用
public class Test06 {
public static void main(String[] args) {
/*Create c1 = new Create() {
@Override
public Car createCar(String name) {
return new Car(name);
}
};*/
// Create c1 = name-> new Car(name);
Create c1 = Car::new;
Car car = c1.createCar("布加迪威龙");
System.out.println(car);
}
@FunctionalInterface //函数式接口
interface Create{
Car createCar(String name);
}
static class Car{
private String name;
public Car(){}
public Car(String name){
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
什么是算法?
- 解决某个实际问题的过程和方法。
学习算法的技巧
- 搞清楚算法的流程
- 直接去推敲如何写代码。
排序算法
- 冒泡排序
- 每次从数组中找出最大值放在数组的后面去。
- 实现冒泡排序的关键步骤分析:
- 假设数组为:int[] arr = {5, 2, 3, 1};
- 确定总共需要几轮:数组的长度-1
- 每轮比较几次;
![image]()
- 当前位置大于后一个位置则交换数据
// 目标:完成冒泡排序。
public class Demo01 {
public static void main(String[] args) {
//1.定义数组
int[] arr = {5, 2, 3 ,1, 4};
//2. 定义一个循环控制冒泡的轮数
for(int i = 0; i < arr.length -1; i++){
// 轮数(i) 每轮比较的次数 j的占位
// 0 4 0 1 2 3
// 1 3 0 1 2
// 2 2 0 1
// 3 1 0
//3. 定义内部循环要控制每轮比较次数
for(int j = 0; j < arr.length - i - j; j++){
// 4.判断当前位置j是否大于其后一个位置处的数据。若较大,则交换。
if(arr[j] > arr[j + 1]){
//5. 定义一个临时变量记住较大的值。
int temp = arr[j];
//6. 把前一个数据赋值给后一个,把临时的变量赋值给前一个。
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
- 选择排序
- 每轮选择当前位置,开始找出后面的较小值与该位置交换。
//目标:实现选择排序
public class Demo02 {
public static void main(String[] args) {
//1. 定义一个数组
int[] arr = {5, 1, 3, 2, 4};
//2. 定义一个循环,控制循环几轮
for (int i = 0; i < arr.length -1; i++) {
//3. 定义一个循环,控制每轮比较几次
/*
* 轮数(i) 次数 j的占位
* 0 4 1 2 3 4
* 1 3 2 3 4
* 2 2 3 4
* 3 1 4
* */
for(int j = i + 1; j < arr.length; j++){
//4. 判断j位置的元素是否小于i位置的元素,如果小于,交换位置
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
排序算法的升级版
//目标:实现选择排序
public class Demo02_2 {
public static void main(String[] args) {
//1. 定义一个数组
int[] arr = {5, 1, 3, 2, 4};
//2. 定义一个循环,控制循环几轮
for (int i = 0; i < arr.length -1; i++) {
int minIndex = i;
for(int j = i + 1; j < arr.length; j++){
//4. 判断j位置的元素是否小于i位置的元素,如果小于,交换位置
if(arr[minIndex] > arr[j]){
minIndex = j;
}
}
if(minIndex != i){
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
System.out.println(Arrays.toString(arr));
}
}
查找算法
- 基本查找/顺序查找
![image]()
注意:在数据量特别大的时候,基本查找这种从前往后挨个找的形式,性能是很差的。
二分查找(折半查找)
- 前提条件:数组中的数据必须是有序的。
- 核心思想:每次排除一般的数据,查询数据的性能明显提高极多。
- 结论:二分查找正常的折半条件应该是开始位置left<=结束位置right。
实现代码:
//目标:实现二分查找
//目标:实现二分查找
public class Demo03 {
public static void main(String[] args) {
int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};
int index = serchDataIndex(arr, 79);
System.out.println("79的索引是:" + index);
int index2 = serchDataIndex(arr, 150);
System.out.println("150的索引是:" + index2);
}
public static int serchDataIndex(int[] arr, int key) {
//1. 定义两个变量,记录要查找的范围
int start = 0;
int end = arr.length - 1;
//2.开始折半查询
while (start <= end) {
int mid = (start + end) / 2;
//3. 判断当前位置的元素与key的大小进行比较
if (arr[mid] == key) return mid;
else if (arr[mid] < key) {
//4. 往右边找:开始的指针更新为mid + 1;
start = mid + 1;
} else if (arr[mid] > key) {
//5. 往左边找:结束的指针更新为mid - 1;
end = mid - 1;
}
}
return -1;
}
}
正则表达式
- 正则表达式是由一些特定的字符组成,代表的是一个规则。
- 作用
- 用来校验数据格式是否合法。
- 在一段文本中查找满足要求的内容。
代码举例
//目标:初步体验,正则表达式的作用
public class RegexTest01 {
public static void main(String[] args) {
System.out.println(checkQQ("23242424"));
System.out.println(checkQQ("2324abcd2424"));
System.out.println(checkQQ2("23242424"));
System.out.println(checkQQ2("2324abcd2424"));
}
//先不用正则表达式来解决
public static boolean checkQQ(String qq) {
//1. 需求:要求这个qq号码必须是5位以上,全部都是数字,不能以0开头
if(qq == null || qq.length() == 0) return false;
//2.判断是否是数字
for(int i = 0; i < qq.length(); i++) {
char c = qq.charAt(i);
if(i == 0 && c == '0') return false;
if(c <'0' || c > '9') return false;
}
return true;
}
//使用正则表达式来解决
public static boolean checkQQ2(String qq){
return qq != null && qq.length() > 5 && qq.matches("[1-9]\\d{5,}");
}
}
匹配正则表达式的方法
- public boolean matches(String regex),判断字符串是否匹配正则表达式,匹配返回true,不匹配返回false。
正则表达式的书写规则



案例:
需求:校验用户输入的电话、邮箱
//目标:使用所学的正则表达式来校验数据的合法性
public class Demo01 {
public static void main(String[] args) {
// checkEmail();
checkPhone();
}
public static void checkPhone() {
Scanner sc = new Scanner(System.in);
while(true){
System.out.println("Enter your Phone Number:");
String phone = sc.next();
//13722162084
//8556355
if(phone.matches("1[3-9]\\d{9}")){
System.out.println("手机号码合法,录入成功!");
break;
}
else{
System.out.println("您输入的手机号码不合法,请重新输入!");
}
}
sc.close();
}
public static void checkEmail() {
Scanner sc = new Scanner(System.in);
while(true){
System.out.println("Enter your email address:");
String email = sc.next();
//adf1234@163.com
//8754264@qq.com
//xunzhao@itdcx.com.cn
if(email.matches("\\w{2,30}@\\w{2,20}(\\.\\w{2,20}){1,2}")){
System.out.println("邮箱地址合法,录入成功!");
break;
}
else{
System.out.println("您输入的邮箱地址不合法,请重新输入!");
}
}
sc.close();
}
}
案例:使用正则表达式查找一段文本中的内容。

需求1:找出所有的电话号、邮箱地址、热线电话。
需求2:把每个邮箱中的用户名爬取出来。
//目标:了解使用正则表达式去文本中的爬取想要的信息
public class Demo02 {
public static void main(String[] args) {
String data = "来IT未来学习Java,\n"+
"电话:18512516758,18512508907\n"+
"或者联系邮箱: boniu@itcast.cn\n"+
"座机电话:01036517895,010-98951256\n"+
"邮箱:bozai@itcast.cn,\n"+
"邮箱2:dlei0009@163.com,\n”+" +
"热线电话:400-618-9090,400-618-4000,\n"+
"4006184000,4006189090\n";
// 需求:从中间爬取出邮箱,手机号,座机号,400电话号。
//1. 定义爬取规则对象,封装爬取格式
Pattern p = Pattern.compile("(1[3-9]\\d{9})|(\\w{2,30}@\\w{2,20}(\\.\\w{2,20}){1,2})"+
"|(0\\d{2,6}-?[1-9]\\d{3,10})|(400-?[1-9]\\d{2,6}-?[1-9]\\d{2,6})");
//2.通过匹配规则对象p与内容data建立联系得到一个匹配器对象
Matcher m = p.matcher(data);
//3. 使用匹配器对象,开始爬取内容
while(m.find()){
String info = m.group();
System.out.println(info);
}
//需求2:把每个邮箱中的用户名爬取出来。
Pattern p1 = Pattern.compile("(\\w{2,30})@\\w{2,20}(\\.\\w{2,20}){1,2}");
//2.通过匹配规则对象p与内容data建立联系得到一个匹配器对象
Matcher m1 = p1.matcher(data);
//3. 使用匹配器对象,开始爬取内容
while(m1.find()){
String info = m1.group(1);//只要爬取出来的邮箱中的第一组括号中的内容
System.out.println(info);
}
}
}
案例2:
public class Demo03 {
public static void main(String[] args) {
String data="欢迎张全蛋光临本系统!他删库并跑路欢迎李二狗子光临本系统!"+
"欢迎马六子光临本系统!它浏览了很多好看的照片!欢迎夏洛光临本系统!他在六点钟送出了一个嘉年华!";
//1. 指定爬取规则对象
Pattern p = Pattern.compile("欢迎(.+?)光临");// 贪婪匹配,最大范围匹配
//2. 让内容和爬取规则建立关系,得到一个匹配器对象。
Matcher m = p.matcher(data);
//3. 开始用匹配器对象爬取内容
while(m.find()){
System.out.println(m.group(1));
}
}
}
搜索替换、分割
- 正则表达式用于搜索替换、分割内容,需要结合String提供的如下方法完成:
![image]()
//目标:了解使用正则表达式搜索替换、内容分割。
public class Demo04 {
public static void main(String[] args) {
//需求:把中间非中文字符替换成“-”
String s1 = "古力娜扎ai8888迪丽热巴99fafas9aa5566马尔扎哈fbbADFFfsfs42425卡尔扎巴";
String result = s1.replaceAll("\\w+", "-");
System.out.println(result);
//需求:把所有名字取出来
String[] names = s1.split("\\w+");
System.out.println(Arrays.toString(names));
}
}





浙公网安备 33010602011771号