1.Lambda表达式
Lambda表达式是JDK8引入的一种函数式编程特性,允许以简洁的语法实现函数式接口(只有一个抽象方法的接口)。
(parameters) -> expression
或
(parameters) -> { statements; }
- 参数列表:可省略参数类型(编译器自动推断),空参数时保留括号。
- 箭头符号
->
:分隔参数和实现逻辑。 - 表达式或代码块:单行表达式可省略大括号和
return
;多行语句需用大括号包裹。
package com.whm.unit13;
public class LambdaTest {
public static void main(String[] args) {
//使用匿名内部类的方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程执行");
}
}).start();
/*匿名内部类缺点
* 1.代码结构复杂
* 2.new生产class文件占用内存高
* 3.需要显示接口抽象方法代码冗余
* */
//使用lambda表达式 格式:(参数) -> {表达式或代码块}
new Thread(() -> System.out.println("正在执行的线程" +
Thread.currentThread().getName())).start();
/*lambda表达式优点
* 1.占用内存低
* 2.语法简洁
* 3.自动类型推断
* */
}
}
package com.whm.unit13;
public class LambdaCase {
public static void main(String[] args) {
//1.无参无返回值
Test1 test1 = () -> System.out.println("Name=Jack");
test1.method();
//2.有参无返回值
Test2 test2 = name -> System.out.println("Name=" + name);
test2.method("Mary");
//3.无参有一个返回值
Test3 test3 = () -> "Name=Anny";
System.out.println(test3.method());
//4.有参有一个返回值
Test4 test4 = name -> name;
System.out.println("Name=" + test4.method("Tom"));
//5.有参有多个返回值
Test5 test5 = (n, m) -> n * m;
System.out.println("Result=" + test5.method(10, 20));
}
}
interface Test1 {
void method();
}
interface Test2 {
void method(String name);
}
interface Test3 {
String method();
}
interface Test4 {
String method(String name);
}
interface Test5 {
int method(int n, int m);
}
1. 替代匿名内部类
// 传统写法
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda写法
Runnable r2 = () -> System.out.println("Hello");
2. 集合操作
List<String> list = Arrays.asList("a", "b", "c");
list.forEach(item -> System.out.println(item));
3. 函数式接口
Collections.sort(list, (s1, s2) -> s1.compareTo(s2));
2.方法引用
进一步简化Lambda,通过::
符号引用已有方法:
- 静态方法引用:
ClassName::staticMethod
- 实例方法引用:
instance::method
- 构造方法引用:
ClassName::new
package com.whm.unit12;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class MethodTest {
public static void main(String[] args) {
Student student=new Student("Jack");
//1.实例方法引用
Supplier<String> supplier=student::getName;
//2.静态方法引用
Function<Double,Long> function=Math::round;
//3.特殊方法引用
Comparator<Integer> comparator=Integer::compareTo;
Function<Student,String> function1=Student::getName;
//4.构造方法引用
Function<String,Student> function2=Student::new;
//5.数组引用
Function<Integer,int[]> function3=int[]::new;
System.out.println(Arrays.toString(function3.apply(10)));
}
}
class Student{
private String name;
public String getName() {
return name;
}
public Student(String name) {
this.name = name;
}
}
3.常见函数式接口
JDK8在java.util.function
包中提供了内置函数式接口:
Predicate<T>
:断言型,boolean test(T t)
Consumer<T>
:消费型,void accept(T t)
Function<T,R>
:函数型,R apply(T t)
Supplier<T>
:供给型,T get()
Predicate<T>:断言型
过滤集合中的元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Predicate<Integer> isEven = num -> num % 2 == 0;
List<Integer> evens = numbers.stream().filter(isEven).collect(Collectors.toList());
// 输出:[2, 4]
说明:通过 test
方法判断元素是否满足条件,常用于数据筛选。
Consumer<T>:消费型
遍历并处理集合元素
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());
names.forEach(printUpperCase);
// 输出:ALICE\nBOB\nCHARLIE
说明:通过 accept
方法对输入参数执行操作,无返回值,适用于日志打印或数据修改。
Function<T, R>:函数型
字符串转整数并计算平方
Function<String, Integer> parseAndSquare = s -> (int) Math.pow(Integer.parseInt(s), 2);
int result = parseAndSquare.apply("3");
// 输出:9
说明:通过 apply
方法将输入类型 T
转换为输出类型 R
,适合数据转换或链式处理。
Supplier<T>:供给型
场景示例:生成随机数
Supplier<Double> randomSupplier = () -> Math.random();
double randomValue = randomSupplier.get();
// 输出:0.0 <= randomValue < 1.0
4.Stream API
常用操作分类
中间操作(返回新 Stream)
-
过滤:
filter(Predicate<T>)
示例:筛选偶数
stream.filter(x -> x % 2 == 0)
-
映射:
map(Function<T,R>)
示例:转为字符串
stream.map(Object::toString)
-
去重:
distinct()
示例:去除重复元素
stream.distinct()
终端操作(触发计算)
-
收集结果:
collect(Collectors.toList())
示例:转为 List
stream.collect(Collectors.toList())
-
遍历:
forEach(Consumer<T>)
示例:打印元素
stream.forEach(System.out::println)
-
聚合:
reduce(BinaryOperator<T>)
示例:求和
stream.reduce(0, Integer::sum)
package com.whm.unit13;
import javax.net.ssl.SSLContext;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamAPITest {
public static void main(String[] args) {
List<Student> list = Arrays.asList(
new Student("Jack", 19, '男'),
new Student("Jack", 21, '女'),
new Student("Anny", 20, '男'),
new Student("Mary", 18, '女'),
new Student("Tom", 22, '男'));
//1.打印所有男生
list.stream().filter(student -> student.getGender() == '男').forEach(System.out::println);
//2.使用 Stream API 打印所有女生的信息。
list.stream().filter(student -> student.getGender() == '女').forEach(System.out::println);
System.out.println("===================");
//3.将学生列表按年龄从低到高排序,并打印结果。
list.stream().sorted((s1, s2) -> s1.getAge() - s2.getAge()).forEach(System.out::println);
//4.使用 map() 提取所有学生的姓名,并将结果收集为一个 List<String>。
System.out.println("===================");
List<String> list1 = list.stream().map(Student -> Student.getName()).toList();
System.out.println(list1);
System.out.println("===================");
//5.使用 Stream 统计男生的数量并输出。
System.out.println("男生数量--->" + list.stream().filter(Student -> Student.getGender() == '男').count());
System.out.println("===================");
//6.使用 Stream 找出年龄最大的学生,并打印其信息。
Optional<Student> optional = list.stream().max((s1, s2) -> s1.getAge() - s2.getAge());
System.out.println(optional.get());
System.out.println("===================");
//7.使用 Collectors.groupingBy() 按性别对学生进行分组,输出一个 Map<Character, List<Student>>。
Map<Character, List<Student>> groupedByGender = list.stream()
.collect(Collectors.groupingBy(Student::getGender));
// 打印结果
System.out.println("按性别分组结果:");
groupedByGender.forEach((gender, students) -> {
System.out.println("性别:" + gender);
students.forEach(System.out::println);
});
System.out.println("===================");
//8.使用 anyMatch() 判断是否存在年龄大于 20 的学生,输出 true 或 false。
System.out.println(list.stream().anyMatch(student -> student.getAge() > 20));
//9.使用 filter() 筛选出姓名为 "Jack" 的学生,并打印结果。
System.out.println("===================");
list.stream().filter(student -> student.getName().equals("Jack")).forEach(System.out::println);
//10.使用 map() 将所有学生的姓名转为大写格式并打印。
System.out.println("===================");
list.stream().map(student -> student.getName().toUpperCase()).forEach(System.out::println);
//11.先按姓名升序排序,如果姓名相同则按年龄升序排序,并打印结果。
System.out.println("===================");
list.stream().sorted(Comparator.comparing(Student::getName)
.thenComparing(Student::getAge))
.forEach(System.out::println);
}
}
class Student {
private String name;
private int age;
private char gender;
public Student() {
}
public Student(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
*
* @return gender
*/
public char getGender() {
return gender;
}
/**
* 设置
*
* @param gender
*/
public void setGender(char gender) {
this.gender = gender;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
}
}
5.Optional
Optional 是 Java 8 引入的一个容器类,用于表示一个值可能存在或可能不存在。它可以避免空指针异常(NullPointerException),使代码更加健壮和清晰。Optional 可以包含非空值,也可以为空。
创建 Optional 对象
使用 Optional.of()
方法创建一个包含非空值的 Optional 对象。如果传入的值为 null,会抛出 NullPointerException
。
Optional<String> optional = Optional.of("Hello");
使用 Optional.ofNullable()
方法创建一个可能为空的 Optional 对象。如果传入的值为 null,返回一个空的 Optional。
Optional<String> optional = Optional.ofNullable(null);
使用 Optional.empty()
方法创建一个空的 Optional 对象。
Optional<String> optional = Optional.empty();
检查 Optional 是否有值
使用 isPresent()
方法检查 Optional 是否包含非空值。
if (optional.isPresent()) {
System.out.println("Value is present: " + optional.get());
}
使用 ifPresent()
方法在值存在时执行操作。
optional.ifPresent(value -> System.out.println("Value is present: " + value));
获取 Optional 的值
使用 get()
方法获取 Optional 中的值。如果 Optional 为空,会抛出 NoSuchElementException
。
String value = optional.get();
使用 orElse()
方法获取 Optional 中的值,如果 Optional 为空,返回默认值。
String value = optional.orElse("Default Value");
使用 orElseGet()
方法获取 Optional 中的值,如果 Optional 为空,通过 Supplier 提供默认值。
String value = optional.orElseGet(() -> "Default Value");
使用 orElseThrow()
方法获取 Optional 中的值,如果 Optional 为空,抛出指定的异常。
String value = optional.orElseThrow(() -> new RuntimeException("Value not present"));
链式操作
使用 map()
方法对 Optional 中的值进行转换。
Optional<String> upperCase = optional.map(String::toUpperCase);
使用 flatMap()
方法对 Optional 中的值进行转换,返回另一个 Optional。
Optional<String> flatMapped = optional.flatMap(value -> Optional.of(value.toUpperCase()));
使用 filter()
方法对 Optional 中的值进行过滤。
Optional<String> filtered = optional.filter(value -> value.length() > 5);
注意事项
Optional 主要用于方法的返回类型,避免返回 null。不推荐用于类的字段或方法的参数。
Optional 的设计目的是为了明确表示可能为空的值,而不是替代所有的 null 检查。滥用 Optional 可能会导致代码复杂化。
7.新增日期时间API
package com.whm.unit13;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class DateAndTimeAPITest {
public static void main(String[] args) {
// 1. 获取当前日期(不带时间)
LocalDate localDate = LocalDate.now();
System.out.println("当前日期:" + localDate);
// 2. 获取当前时间(不带日期)
LocalTime localTime = LocalTime.now();
System.out.println("当前时间:" + localTime);
// 3. 获取当前日期和时间(不带时区)
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("当前日期时间:" + localDateTime);
// 4. 使用 DateTimeFormatter 格式化日期时间
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = localDateTime.format(dateTimeFormatter);
System.out.println("格式化日期时间:" + format);
// 5. 解析字符串为日期时间
String str = "2025-07-20 07:47:26";
LocalDateTime parse = LocalDateTime.parse(str, dateTimeFormatter);
System.out.println("解析后的日期时间:" + parse);
// 6. 计算日期加减
LocalDateTime localDateTime1 = localDateTime.plusDays(1);
System.out.println("明天日期:" + localDateTime1.format(dateTimeFormatter));
LocalDateTime localDateTime2 = localDateTime.plusMonths(1);
System.out.println("下个月是:" + localDateTime2.format(dateTimeFormatter));
// 7. 计算两个日期之间的天数差
LocalDate date1 = LocalDate.of(2025, 1, 1);
LocalDate date2 = LocalDate.of(2026, 1, 1);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println("两个日期之间的天数差: " + daysBetween);
// 8. 获取当前时间戳(Instant)
Instant now = Instant.now();
System.out.println("当前时间戳:" + now);
// 9. 带时区的时间
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("带时区的时间: " + zonedDateTime);
}
}
8.接口优化
默认方法(Default Methods)
默认方法允许在接口中提供方法的默认实现,子类可以直接使用或重写。语法格式为:
public interface MyInterface {
default void defaultMethod() {
System.out.println("默认方法实现");
}
}
关键点:
- 使用
default
关键字修饰。 - 子类可直接调用或通过
@Override
重写。 - 解决接口升级时兼容性问题:新增默认方法不会强制现有实现类修改代码。
多继承冲突:若一个类实现多个接口且存在同名默认方法,需显式指定或重写。例如:
@Override
public void defaultMethod() {
InterfaceA.super.defaultMethod(); // 显式选择接口A的实现
}
静态方法(Static Methods)
接口中可定义静态方法,直接通过接口名调用,不属于实现类。语法格式为:
public interface MyInterface {
static void staticMethod() {
System.out.println("静态方法调用");
}
}
关键点:
- 使用
static
关键字修饰。 - 仅能通过接口名调用(如
MyInterface.staticMethod()
),无法通过实现类实例调用。 - 提供工具方法:例如
Collections.sort()
在 JDK 8 后可通过接口静态方法实现。