Java 8 引入了很多新的特性,极大地增强了 Java 语言的表达能力和开发效率。以下是一些主要的新特性
1.Lambda 表达式
Lambda 表达式允许以更简洁的方式表示匿名函数,使得代码更加简洁和可读。它支持函数式编程风格,并可以作为参数传递给方法。
语法:
(parameters) -> expression
示例:
// 使用Lambda表达式表示Runnable接口
// Lambda 表达式 无参数:如果没有参数,可以省略括号
// 一个参数:如果只有一个参数,括号可以省略。 x -> x * x //传入一个参数并返回其平方
// 多个参数:多个参数时需要使用括号来包含。(x, y) -> x + y //传入两个参数并返回它们的和
// 带有代码块:如果 Lambda 表达式的主体包含多个语句,需要使用大括号 {} 来包裹代码块
// (x, y) -> {
// int sum = x + y;
// return sum;
// }
Runnable
r = () -> System.out.println("Hello from Lambda");
r.run();
Lambda 表达式的优势
- 简化代码:Lambda 表达式使得代码更加简洁,减少了冗长的匿名类代码。
- 提高可读性:通过明确的行为表达式,Lambda 让代码变得更加直观和易于理解。
- 支持函数式编程:Lambda 表达式使得 Java 更好地支持函数式编程,支持高阶函数、组合函数等。
- 与 Stream API 结合使用:与 Java 8 引入的 Stream API 结合,Lambda 可以方便地处理集合数据,进行过滤、映射、排序等操作。
Lambda 表达式的实际应用场景
- 集合框架:通过 Lambda 表达式简化集合元素的操作,特别是在 List、Set、Map 等集合上进行过滤、映射、排序等操作。
- 事件处理:在 GUI 编程中,Lambda 可以简化事件监听器的实现。
- 函数式接口:Java 8 中定义了很多函数式接口(如 Runnable、Callable、Comparator 等),可以通过 Lambda 表达式来简化它们的实现。
2.Java 8 java.util.function
包及常见接口详解
Java 8 引入了 java.util.function
包,该包提供了一组核心函数式接口,支持 Lambda 表达式和方法引用。这些接口简化了代码,使其更加简洁、可读和易于维护。
常用的函数式接口一览
接口名 | 描述 | 函数式方法 |
---|---|---|
Predicate<T> | 条件判断(过滤) | boolean test(T) |
Function<T, R> | 类型转换(映射) | R apply(T) |
Consumer<T> | 消费型操作(无返回) | void accept(T) |
Supplier<T> | 供给型操作(返回数据) | T get() |
UnaryOperator<T> | 一元运算符(同类型转换) | T apply(T) |
BinaryOperator<T> | 二元运算符(同类型运算) | T apply(T, T) |
1. Predicate<T>
:条件判断
Predicate<T>
用于条件判断,常用于过滤操作。
核心方法:
boolean test(T t)
:对给定的输入执行判断,返回布尔值。
默认方法:
and(Predicate other)
:逻辑与操作。or(Predicate other)
:逻辑或操作。negate()
:逻辑非操作。
示例:判断字符串是否为空
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
System.out.println(isEmpty.test("")); // 输出: true
System.out.println(isNotEmpty.test("Java")); // 输出: true
}
}
2. Function<T, R>
:类型转换
Function<T, R>
用于将一个类型转换为另一个类型,常用于映射操作。
核心方法:
R apply(T t)
:将输入参数T
转换为结果R
。
默认方法:
andThen(Function after)
:在当前函数执行后执行另一个函数。compose(Function before)
:在当前函数执行前执行另一个函数。
示例:字符串长度映射与组合
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> strLength = String::length;
Function<Integer, Integer> doubleValue = x -> x * 2;
System.out.println(strLength.apply("Java")); // 输出: 4
System.out.println(strLength.andThen(doubleValue).apply("Java")); // 输出: 8
}
}
3. Consumer<T>
:数据消费
Consumer<T>
用于操作数据,没有返回值,常用于打印或存储。
核心方法:
void accept(T t)
:接收参数并执行操作。
默认方法:
andThen(Consumer after)
:组合多个消费者操作。
示例:打印数据并组合操作
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printer = System.out::println;
Consumer<String> greeter = name -> System.out.println("Hello, " + name);
printer.accept("Java!"); // 输出: Java!
greeter.andThen(printer).accept("World"); // 输出: Hello, World
// 输出: World
}
}
4. Supplier<T>
:数据提供
Supplier<T>
提供数据,没有输入参数,常用于生成数据。
核心方法:
T get()
:返回一个结果。
示例:生成随机数与当前时间
import java.util.function.Supplier;
import java.util.Random;
public class SupplierExample {
public static void main(String[] args) {
Supplier<Integer> randomNumber = () -> new Random().nextInt(100);
Supplier<Long> currentTime = System::currentTimeMillis;
System.out.println("随机数: " + randomNumber.get()); // 输出: 随机整数
System.out.println("当前时间: " + currentTime.get()); // 输出: 当前时间戳
}
}
5. UnaryOperator<T>
:一元运算
UnaryOperator<T>
是特殊的 Function<T, T>
,用于相同类型的数据转换。
核心方法:
T apply(T t)
:将输入参数T
转换为T
。
示例:将字符串转换为大写
import java.util.function.UnaryOperator;
public class UnaryOperatorExample {
public static void main(String[] args) {
UnaryOperator<String> toUpperCase = String::toUpperCase;
System.out.println(toUpperCase.apply("java")); // 输出: JAVA
}
}
6. BinaryOperator<T>
:二元运算
BinaryOperator<T>
是特殊的 BiFunction<T, T, T>
,用于两个相同类型的数据运算。
核心方法:
T apply(T t1, T t2)
:对两个参数执行操作并返回结果。
示例:两个整数相加与最大值比较
import java.util.function.BinaryOperator;
public class BinaryOperatorExample {
public static void main(String[] args) {
BinaryOperator<Integer> add = Integer::sum;
BinaryOperator<Integer> max = Integer::max;
System.out.println("求和: " + add.apply(5, 3)); // 输出: 8
System.out.println("最大值: " + max.apply(5, 3)); // 输出: 5
}
}
总结
java.util.function
包提供的接口能够帮助我们以更加简洁的方式实现函数式编程。Lambda
表达式和这些接口的结合,使得代码更加简洁和易于理解。熟练掌握这些接口,可以在日常开发中写出更优雅的代码。
Java Stream API 深入解析与实用示例
Java 8 引入了 Stream API,极大简化了对集合数据的处理。通过流操作,开发者可以实现复杂的数据操作,如过滤、排序和聚合,代码更简洁、更具可读性。
3.什么是 Stream API?
Stream API
提供了一种函数式编程风格的数据处理方式,主要用于对集合数据(如 List
, Set
, Map
)进行操作。它支持以下功能:
- 过滤(Filtering)
- 映射(Mapping)
- 排序(Sorting)
- 统计与聚合(Reduction)
- 收集结果(Collecting)
Stream 流的生命周期
Stream 的使用包含以下三个步骤:
- 创建流 (Stream Source): 从集合、数组等数据源创建流。
- 中间操作 (Intermediate Operations): 对数据执行链式转换操作。
- 终止操作 (Terminal Operations): 执行终结操作,如收集结果或计算。
3.Stream 的常见操作与示例
1. 创建流 (Stream Creation)
-
从集合创建流:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Stream<String> nameStream = names.stream();
-
从数组创建流:
int[] numbers = {1, 2, 3, 4, 5}; IntStream numberStream = Arrays.stream(numbers);
-
使用
Stream.of()
方法:Stream<String> stream = Stream.of("Java", "Python", "C++");
2. 中间操作 (Intermediate Operations)
1. 过滤 (filter)
- 过滤出长度大于 3 的字符串:
List<String> names = Arrays.asList("Java", "C", "Python", "Go"); names.stream() .filter(name -> name.length() > 2) .forEach(System.out::println);
2. 映射 (map)
- 将字符串转换为大写:
List<String> languages = Arrays.asList("java", "python", "go"); languages.stream() .map(String::toUpperCase) .forEach(System.out::println);
3. 排序 (sorted)
- 按字母顺序排序:
List<String> fruits = Arrays.asList("Apple", "Orange", "Banana"); fruits.stream() .sorted() .forEach(System.out::println);
4. 去重 (distinct)
- 去除重复的元素:
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4); numbers.stream() .distinct() .forEach(System.out::println);
5. 限制和跳过 (limit / skip)
-
获取前两个元素:
Stream.of("A", "B", "C", "D") .limit(2) .forEach(System.out::println);
-
跳过前两个元素:
Stream.of("A", "B", "C", "D") .skip(2) .forEach(System.out::println);
3. 终结操作 (Terminal Operations)
1. 收集 (collect)
- 将流转换为集合:
List<String> filteredNames = names.stream() .filter(name -> name.length() > 3) .collect(Collectors.toList()); System.out.println(filteredNames);
2. 统计 (count)
- 统计列表中以 “J” 开头的名字数量:
long count = names.stream() .filter(name -> name.startsWith("J")) .count(); System.out.println("数量: " + count);
3. 匹配 (anyMatch / allMatch / noneMatch)
- 检查是否有任何字符串以 “A” 开头:
boolean exists = names.stream() .anyMatch(name -> name.startsWith("A")); System.out.println("存在: " + exists);
4. 查找 (findFirst / findAny)
- 获取第一个元素:
Optional<String> first = names.stream().findFirst(); first.ifPresent(System.out::println);
5. 归约 (reduce)
- 计算总和:
int sum = IntStream.range(1, 6) .reduce(0, Integer::sum); System.out.println("总和: " + sum);
示例:完整案例演示
示例:获取学生平均成绩
import java.util.*;
import java.util.stream.*;
public class StreamExample {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Alice", 85),
new Student("Bob", 90),
new Student("Charlie", 75)
);
double averageScore = students.stream()
.mapToInt(Student::getScore)
.average()
.orElse(0);
System.out.println("平均成绩: " + averageScore);
}
}
class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
}
总结
Java 8 Stream API 提供了强大的数据操作功能,支持链式操作和多种聚合操作。熟练掌握 Stream API,可以大幅提高数据处理的效率和代码的简洁性。
4.Java Optional
类详解与使用示例
Java 8 引入了 Optional
类,旨在减少 NullPointerException
的出现,优雅地处理可能为空的值。它是一个容器类,表示一个可能包含值或为空的对象。
什么是 Optional
?
Optional<T>
是一个容器对象,它可能包含一个非空值,也可能为空。Optional
提供了多种方法来避免显式的 null
检查,从而减少冗余代码,提高代码的可读性和健壮性。
创建 Optional
实例的方式
1. Optional.of(T value)
- 创建一个包含非空值的
Optional
对象。 - 如果传入值为
null
,则抛出NullPointerException
。
Optional<String> optional = Optional.of("Java");
2. Optional.ofNullable(T value)
- 创建一个可能包含
null
的Optional
对象。 - 如果传入值为
null
,则返回一个空的Optional
。
Optional<String> optional = Optional.ofNullable(null); // 空的 Optional
Optional<String> optional2 = Optional.ofNullable("Hello"); // 非空的 Optional
3. Optional.empty()
- 创建一个空的
Optional
对象。
Optional<String> emptyOptional = Optional.empty();
常用方法与示例
1. isPresent()
和 ifPresent()
isPresent()
: 检查值是否存在,返回布尔值。ifPresent(Consumer)
: 如果值存在,执行传入的操作。
Optional<String> optional = Optional.of("Java");
if (optional.isPresent()) {
System.out.println("存在值: " + optional.get());
}
optional.ifPresent(value -> System.out.println("值存在: " + value));
2. get()
- 获取
Optional
中的值,如果为空则抛出NoSuchElementException
。
Optional<String> optional = Optional.of("Java");
System.out.println(optional.get()); // 输出: Java
3. orElse(T other)
- 如果值存在则返回该值,否则返回默认值。
Optional<String> optional = Optional.ofNullable(null);
System.out.println(optional.orElse("默认值")); // 输出: 默认值
4. orElseGet(Supplier)
- 如果值存在则返回该值,否则执行
Supplier
函数生成默认值。
Optional<String> optional = Optional.ofNullable(null);
System.out.println(optional.orElseGet(() -> "动态生成默认值"));
5. orElseThrow(Supplier)
- 如果值存在则返回该值,否则抛出由
Supplier
提供的异常。
Optional<String> optional = Optional.ofNullable(null);
optional.orElseThrow(() -> new IllegalArgumentException("值不存在"));
6. filter(Predicate)
- 根据条件过滤
Optional
值,如果不满足条件则返回空的Optional
。
Optional<String> optional = Optional.of("Java");
optional.filter(value -> value.startsWith("J"))
.ifPresent(System.out::println); // 输出: Java
7. map(Function)
- 对
Optional
中的值执行转换操作,返回新的Optional
。
Optional<String> optional = Optional.of("Java");
Optional<Integer> length = optional.map(String::length);
System.out.println("长度: " + length.orElse(0)); // 输出: 长度: 4
8. flatMap(Function)
- 与
map
类似,但要求返回值必须是Optional
。
Optional<String> optional = Optional.of("Java");
Optional<String> upper = optional.flatMap(value -> Optional.of(value.toUpperCase()));
System.out.println(upper.orElse("空值")); // 输出: JAVA
完整示例:用户信息管理
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
User user = new User("Alice", "alice@example.com");
// 使用 Optional 处理可能为空的字段
String email = Optional.ofNullable(user)
.map(User::getEmail)
.orElse("未提供邮箱");
System.out.println("用户邮箱: " + email);
}
}
class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
何时使用 Optional
?
-
适用场景:
- 方法返回值可能为空。
- 需要避免
null
检查,增强代码的可读性。
-
不适用场景:
- 在类的字段中使用(如实体类中的属性)。
- 不应滥用,以避免不必要的性能开销。
总结
Optional
是处理可能为空的对象的强大工具,提供了灵活的空值处理方式,避免了繁琐的 null
检查。熟练掌握 Optional
的方法,可以编写更简洁、更健壮的 Java 代码。