1. JDK8新特性、算法
1.1 JDK8新特性:Lambda表达式
Lambda表达式是JDK8开始新增的一种语法形式;
作用:用于简化匿名内部类的代码写法。
注意:Lambda表达式只能简化函数式接口的匿名内部类!!!
1.2 Lambda表达式的省略规则
- 参数类型可以省略不写。
- 如果只有一个参数,参数类型可以省略,同时()也可以省略。
- 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如
果这行代码是return语句,也必须去掉return不写。
1.3 JDK8新特性:方法引用
1.3.1 静态方法引用
类名::静态方法
如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。
1.3.2 实例方法引用
对象名::实例方法
如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用。
1.4 JDK8新特性:特定类型的方法引用
类型::方法
如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调
后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
1.5 JDK8新特性:构造器引用
类名::new
如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。
1.6 算法:简单认识算法
算法就是解决某个实际问题的过程和方法。
1.7 算法:排序算法-冒泡排序
package com.itheima.algorithm;
import java.util.Arrays;
/**
* @ClassName BubbleSort
* @Description 冒泡排序
* @Author 孙克旭
* @Date 2025/3/23 17:26
*/
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {10, 2, 14, 5, 9, 12};
//1.确定冒泡的轮数:元素个数-1
for (int i = 0; i < arr.length - 1; i++) {
//2.确定每轮比较数据的次数
for (int j = 0; j < arr.length - i - 1; j++) {
//3.如果左边元素大于右边,则交换
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
//4.输出结果
System.out.println(Arrays.toString(arr)); //[2, 5, 9, 10, 12, 14]
}
}
1.8 算法:排序算法-选择排序
package com.itheima.algorithm;
import java.util.Arrays;
/**
* @ClassName SelectionSort
* @Description 选择排序
* @Author 孙克旭
* @Date 2025/3/23 17:44
*/
public class SelectionSort {
public static void main(String[] args) {
int[] arr = {10, 2, 14, 5, 9, 12};
//1.确定循环几轮:数组长度-1
for (int i = 0; i < arr.length - 1; i++) { //i表示当前元素下标
//2.每一轮需要比较的次数
for (int j = i + 1; j < arr.length; j++) { //j表示需要与当前元素比较的元素下标
//3.如果左边元素大于右边,则交换
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
//4.输出结果
System.out.println(Arrays.toString(arr)); //[2, 5, 9, 10, 12, 14]
}
}
1.9 课后练习
1.9.1 题目一
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
请阅读如下代码:
class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
// 省略 getters and setters
// 比较两个学生对象年龄的方法
public static int compareByAge(Student s1, Student s2) {
return s1.age.compareTo(s2.age);
}
}
假设我们现在有一个Student对象数组,要按照学生的年龄从小到大排序:
public class Test {
public static void main(String[] args) {
Student[] students = {
new Student("Tom", 20),
new Student("Jerry", 18),
new Student("Lily", 19),
new Student("Lucy", 22),
new Student("kevin", 21)};
// 使用匿名内部类
/*
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge().compareTo(s2.getAge());
}
});
*/
// 第一步,使用Lambda表达式改写
// 第二步,使用方法引用改写
// 遍历
for (Student student : students) {
System.out.println(student.getName() + " - " + student.getAge());
}
}
}
我们可以使用匿名内部类的方式,传递Comparator的子类对象,实现排序。而Comparator是一个函数式接口,请先使用Lambda表达式改写中间被注释的排序代码,实现相同的需求。
然后我们还发现,关于两个年龄的比较方法,已经在Student类中实现了,因此,我们可以直接使用已存在的Student.compareByAge方法,请继续采用方法引用的方式改写排序代码,实现相同的需求。
// 使用Lambda表达式
// Arrays.sort(students, (s1, s2) -> s1.getAge().compareTo(s2.getAge()));
// 使用方法引用
Arrays.sort(students, Student::compareByAge);
1.9.2 题目二
请观察如下代码,其实现的效果是将数组中的元素按照从大到小的顺序排序:
public class Test {
public static void main(String[] args) {
Integer[] arr = {2, 4, 6, 1, 9, 3, 0, 7};
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
return i2.compareTo(i1);
}
});
System.out.println(Arrays.toString(arr));
}
}
请使用Lambda表达式,改写以上代码,实现相同的需求。
Arrays.sort(arr, (i1, i2) -> i2.compareTo(i1));
// Arrays.sort(arr, (i1, i2) -> i2 - i1);
1.10 单元练习13
1.10.1 Lambda表达式和匿名内部类的区别是什么?
①语法:Lambda表达式使用箭头符号“->”定义,而匿名内部类使用关键字“new”来创建一个对象;
②类型推断:Lambda表达式可以自动推断参数类型和返回类型,而匿名内部类需要显式地声明接口或抽象类的类型;
1.10.2 什么是方法引用?方法引用的常见格式都有哪些?
方法引用是Java 8中的一项新特性,它可以简化Lambda表达式的写法。方法引用提供了一种更加简洁的方式来调用已有的方法。
方法引用可以在Lambda表达式中使用,用于直接引用一个已经存在的方法,而不是在Lambda表达式中重新定义一个lambda体。方法引用有以下四种形式:
①静态方法引用:Class::staticMethod
②实例方法引用:instance::instanceMethod
③构造方法引用:Class::new
④特定类型方法引用:String::compareToIgnoreCase
1.10.3 编码题1
使用Arrays.sort方法,对一个字符串数组进行排序,要求按照字符串长度从小到大排序。分别用下面两种方式实现
①使用lambda表达式实现
②编写CompareByData类,在里面定义静态比较方法,使用静态方法引用简化lambda写法
import java.util.Arrays;
public class LambdaDemo1 {
// 请写一个lambda表达式,用于对一个字符串列表进行排序,要求按照字符串长度从小到大排序。
// ①使用lambda表达式实现
// ②使用静态方法引用简化lambda写法
public static void main(String[] args) {
String[] stringList = new String[]{"Java", "Python", "JavaScript", "C++"};
Arrays.sort(stringList, (s1,s2)-> s1.length()-s2.length());
System.out.println("lambda排序效果:"+Arrays.toString(stringList));
Arrays.sort(stringList, CompareByData::compareLength);
System.out.println("静态方法引用排序效果:"+Arrays.toString(stringList));
}
}
public class CompareByData {
public static int compareLength(String s1, String s2) {
return s1.length() - s2.length();
}
}
1.10.4 编码题2
使用Arrays.sort方法,对一个字符串数组进行升序排序,要求忽略首字符大小写排序,请特定类型的方法引用简化lambda写法
public static void main(String[] args) {
//1,准备字符串数组
String[] str = {"Andy","angela","abc","cindy","hb","Bond"};
//2,进行升序排序,要求忽略首字符大小写排序,请使用特定类型的方法引用简化lambda写法
/*Arrays.sort(str,(s1,s2)->{
return s1.compareToIgnoreCase(s2);
});*/
// Arrays.sort(str,(s1,s2)->s1.compareToIgnoreCase(s2));
Arrays.sort(str,String::compareToIgnoreCase);
System.out.println(Arrays.toString(str));
}
2. 算法、正则表达式
2.1 算法:查找算法-二分查找
package com.itheima.algorithm;
/**
* @ClassName BinarySearch
* @Description 二分查找
* @Author 孙克旭
* @Date 2025/3/24 7:52
*/
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {2, 5, 9, 10, 12, 14}; //有序队列
System.out.println(BinarySearchFunction(arr, 12)); //4
}
/**
* 二分查找算法
*
* @param arr
* @param i
*/
private static int BinarySearchFunction(int[] arr, int i) {
//1.定义两个指针,表示左端和右端的下标
int left = 0, right = arr.length - 1;
//2.定义循环规则:左端指针<=右端指针
while (left <= right) {
//3.计算中间值
int middle = (left + right) / 2;
if (arr[middle] == i) { //如果该值与目标值相等
return middle;
} else if (arr[middle] > i) { //继续找左侧区间
right = middle - 1;
} else { //继续找右侧区间
left = middle + 1;
}
}
//4.最后表示没有找到目标值
return -1;
}
}
2.2 正则表达式:概述、初体验
package com.itheima.regex;
/**
* @ClassName Demo1
* @Description 检查qq号
* @Author 孙克旭
* @Date 2025/3/24 8:35
*/
public class Demo1 {
public static void main(String[] args) {
boolean flag = checkQQ("2554798585");
System.out.println(flag); //true
}
private static boolean checkQQ(String s) {
//qq号是6到20位
return s != null && s.matches("[0-9]\\d{5,19}");
}
}
2.3 正则表达式:匹配规则
语法规则
特殊字符
^ :为匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"\n"或"\r"之后的位置匹配。 $ :为匹配输入字符串的结束位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。 \ :转义符 [ ] :表示一个区间,区间的范围可以自己定义
正则表达式的字符类
[abc] :代表a或者b,或者c字符中的一个。 [^abc] :代表除a,b,c以外的任何字符。 [a-z] :代表a-z的所有小写字符中的一个。 [A-Z] :代表A-Z的所有大写字符中的一个。 [0-9] :代表0-9之间的某一个数字字符。 [a-zA-Z0-9] :代表a-z或者A-Z或者0-9之间的任意一个字符。 [a-dm-p] :a 到 d 或 m 到 p之间的任意一个字符。
正则表达式的逻辑运算符
&& :并且。多个条件同时满足 || :或者。满足其中一个条件即可
正则表达式的预定义字符类
在正则中已经定义好的一些有特殊含义的字符,可以直接使用"." :匹配任何字符(常用) "\\d" :任何数字[0-9]的简写(常用) "\\D" :任何非数字[^0-9]的简写 "\\w" :单词字符:[a-zA-Z_0-9]的简写 (常用) "\\W" :非单词字符:[^\w] 的简写 "\\s" :空白字符(空格):[ \t\n\x0B\f\r] 的简写 "\\S" :非空白字符:[^\s] 的简写
注意:在正则表达式中,写 \ 的时候,需要写两个 \,因为 \ 本身是一个转义字符
正则表达式的限定符(数量词)
X* : 0次到多次 任意次 X? : 0次或1次 0,1 X+ : 1次或多次 X>=1 X{n} : 恰好n次 X==n次 X{n,} : 至少n次 X>=n次 X{n,m} : n到m次(n和m都是包含的) n=<X<=m
正则表达式的分组括号 ( )
// 示例:校验字符串"abc"可以出现任意次 String regex = "(abc)*";
2.4 正则表达式:应用案例
需求:校验用户输入的电话、邮箱、时间是否合法。
package com.itheima.regex;
import java.util.Scanner;
/**
* @ClassName Demo2
* @Description 案例
* @Author 孙克旭
* @Date 2025/3/24 19:51
*/
public class Demo2 {
public static void main(String[] args) {
checkEmail();
}
public static void checkPhone() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入电话号码(手机|座机):");
String phone = scanner.next();
if (phone.matches("(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})")) {
System.out.println("电话号码正确!");
break;
} else {
System.out.println("电话号码错误!");
}
}
}
public static void checkEmail() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入邮箱号:");
String phone = scanner.next();
if (phone.matches("\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}")) {
System.out.println("邮箱正确!");
break;
} else {
System.out.println("邮箱错误!");
}
}
}
}