函数式接口与Lambda
定义:函数式接口是只有一个抽象方法的接口。通过 @FunctionalInterface
注解可以限制接口只能有一个抽象方法。
Lambda 表达式让 Java 支持了函数式编程风格,使得代码更加简洁,并大大简化了对接口的实现。我们一起来看看它支持那些地方使用。
目的: 函数式接口的设计目的是为了能够将其作为 Lambda 表达式的目标类型,从而实现函数式编程的风格。
以下有几个函数式接口和Lambda表达式应用的例子。
Predicate< T >
Predicate
接口表示一个接受单个参数并返回 boolean
值的断言,用于条件判断。
- 方法:
boolean test(T t)
- 常用场景: 过滤数据、条件判断等。
Predicate<Integer> isEven = x -> x % 2 == 0;
System.out.println(isEven.test(4)); // 输出: true
System.out.println(isEven.test(5)); // 输出: false
Consumer< T >
Consumer
接口表示一个接受单个输入参数并进行某些操作,但不返回结果的操作。
- 方法:
void accept(T t)
- 常用场景: 用于执行某个操作,如打印、存储、操作数据。
Consumer<Integer> consumer = age -> System.out.println(age);
consumer.accept(5); //输出:5
Supplier< T >
Supplier
接口表示一个无参的提供者,返回特定类型的结果。
- 方法:
T get()
- 常用场景: 延迟计算、创建新对象等。
Supplier<Integer> supplier = () -> new Random().nextInt();
System.out.println(supplier.get());
Function<T, R>
Function
接口表示一个接受一个输入参数并返回结果的函数。
- 方法:
R apply(T t)
- 常用场景: 用于转换、映射操作。
Function<String, Integer> stringLength = (s) -> s.length();
System.out.println(stringLength.apply("Hello")); // 输出: 5
总结
Predicate<T>
用于条件判断。Consumer<T>
用于消费数据,不返回结果。Supplier<T>
用于提供数据。Function<T, R>
用于输入输出转换。
Stream API
定义:Stream API 用于处理集合数据,支持链式操作,能够更方便地进行过滤、排序、映射等操作。
创建 Stream
Stream.of(T... values)
: 创建一个包含给定元素的流。- Collection.stream():通过一个集合创建一个流。
Stream<Integer> integerStream = Stream.of(1, 2, 3);
integerStream.forEach(System.out::println);
List<Integer> integerList = Arrays.asList(1, 2, 3);
integerList.stream().forEach(System.out::println);
中间操作
filter(Predicate<? super T> predicate)
: 过滤出符合条件的元素。
List<Integer> integerList = Arrays.asList(1, 2, 3);
integerList.stream()
.filter( x -> x % 2 == 0 ); //只剩能整除2的数
map(Function<? super T, ? extends R> mapper)
: 将每个元素映射为另一个对象。
List<String> list = Arrays.asList("A", "B", "C");
list.stream()
.map(String::toLowerCase)
.forEach(System.out::println); // 输出: a b c
sorted()
: 对流中的元素进行排序。
java复制代码List<String> list = Arrays.asList("B", "A", "C");
list.stream()
.sorted()
.forEach(System.out::println); // 输出: A B C
终止操作
这些操作会产生一个结果或副作用,并关闭流。
forEach(Consumer<? super T> action)
: 对每个元素执行操作。
List<String> list = Arrays.asList("A", "B", "C");
list.stream()
.forEach(System.out::println); // 输出: A B C
collect(Collector<? super T, A, R> collector)
: 将流的元素收集到集合中。
List<String> list = Arrays.asList("A", "B", "C");
List<String> result = list.stream()
.collect(Collectors.toList());
System.out.println(result); // 输出: [A, B, C]
count()
: 返回流中元素的数量。
List<String> list = Arrays.asList("A", "B", "C");
long count = list.stream().count();
System.out.println(count); // 输出: 3
日期时间 API
LocalDate:表示没有时间的日期(年、月、日)。
LocalTime:表示没有日期的时间(小时、分钟、秒)。
LocalDateTime:表示日期和时间的组合。
ZonedDateTime:表示包含时区的日期时间。
常用方法
-
获取当前日期和时间
LocalDate today = LocalDate.now(); LocalTime now = LocalTime.now(); LocalDateTime nowDateTime = LocalDateTime.now(); ZonedDateTime nowZoned = ZonedDateTime.now();
-
格式化日期时间 使用
DateTimeFormatter
类来格式化和解析日期时间。示例:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate date = LocalDate.parse("2024-10-28", formatter); System.out.println(date); // 输出: 2024-10-28
-
日期时间的加减
LocalDate nextWeek = LocalDate.now().plusWeeks(1); LocalDate previousMonth = LocalDate.now().minusMonths(1);
-
比较日期和时间
LocalDate date1 = LocalDate.of(2024, 1, 1); LocalDate date2 = LocalDate.of(2024, 10, 28); boolean isBefore = date1.isBefore(date2); // true boolean isAfter = date1.isAfter(date2); // false
接口默认方法
定义与语法
-
默认方法使用default关键字来定义,其语法结构如下:
public interface MyInterface { default void myDefaultMethod() { System.out.println("This is a default method"); } }
特性
- 可选实现:实现该接口的类可以选择重写默认方法,也可以直接使用接口提供的默认实现。
- 多重继承:如果一个类实现了多个接口,且这些接口中都有同名的默认方法,编译器会报错,此时需要在实现类中显式重写该方法以消除歧义。
优点
- 向后兼容性:可以在接口中添加新方法而不影响已有的实现类,确保向后兼容。
- 减少代码重复:可以为多个实现类提供通用的功能,减少代码的重复。
- 灵活性:实现类可以选择重写或使用默认实现,提供了灵活的设计。
使用场景
- API 设计:当需要为接口添加新功能而不破坏已有实现时,可以使用默认方法。
- 提供通用功能:在接口中实现一些通用功能,供实现类直接使用。
Optional 类
-
定义:
Optional
类用来解决可能出现的NullPointerException
问题,通过显式的空值检查方式,提供更安全的编程方式。Optional<String> name = Optional.ofNullable(null); name.ifPresent(System.out::println);
-
作用:避免 null 值引发的异常,增强代码的健壮性和可读性。
并行 (Parallel) Stream
-
定义:
parallelStream
可以并行化处理流操作,提高处理大数据集合时的性能。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.parallelStream().forEach(System.out::println);
-
作用:充分利用多核 CPU 资源,在并发环境下实现数据流的高效处理。
Metaspace
- 定义:JDK 8 用 Metaspace 取代了永久代 (PermGen),使类元数据存储在本地内存而非堆中。
- 作用:避免 PermGen 容量固定的缺陷,提升内存管理的灵活性。