你好呀,欢迎来到 Dong雨 的技术小栈 🌱
在这里,我们一同探索代码的奥秘,感受技术的魅力 ✨。
👉 我的小世界:Dong雨
📌 分享我的学习旅程
🛠️ 提供贴心的实用工具
💡 记录每一个灵感火花
🌟✨ Hello,探索技术的你,这里是本篇的地图指南! ✨🌟
目录
🌟✨ Hello,探索技术的你,这里是本篇的地图指南! ✨🌟
1.2.6 anyMatch(), allMatch(), noneMatch()
2.3.1 使用 Optional 返回可能为 null 的值
2.2. Optional 的方法可以与 Stream 配合使用
1. Stream 流
背景
Stream
是Java 8引入的一个用于处理集合(或其他数据源)中的元素的API。它提供了一种声明式的方式来处理数据,并可以链式调用。Stream
支持惰性求值,也支持并行流处理。
1.1 创建 Stream
创建一个Stream可以通过多种方式,不同的数据源(如集合、数组、生成器等)提供了不同的创建方法。
1.1.1 使用集合创建 Stream
- 方法:
stream()
方法可以用于集合类,如List
、Set
等,返回一个顺序流。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println); // 输出 1, 2, 3, 4, 5
1.1.2 使用 Arrays 创建 Stream
- 方法:
Arrays.stream()
可以从数组创建 Stream。
int[] numbers = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(numbers);
stream.forEach(System.out::println); // 输出 1, 2, 3, 4, 5
1.1.3 使用 Stream.of()
- 方法:
Stream.of()
创建包含指定元素的Stream。
Stream<String> stream = Stream.of("Apple", "Banana", "Cherry");
stream.forEach(System.out::println); // 输出 Apple, Banana, Cherry
1.1.4 使用生成器
- 方法:
Stream.generate()
和Stream.iterate()
用于生成无限流。
Stream<Double> randomNumbers = Stream.generate(Math::random);
randomNumbers.limit(5).forEach(System.out::println); // 输出5个随机数
Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2);
evenNumbers.limit(5).forEach(System.out::println); // 输出 0, 2, 4, 6, 8
1.2 中间操作
中间操作是惰性求值的,它们返回一个新的Stream对象,允许链式调用。常见的中间操作包括 filter()
, map()
, flatMap()
, distinct()
, sorted()
等。
1.2.1 filter()
- 作用:过滤出符合条件的元素。
- 签名:
Stream<T> filter(Predicate<? super T> predicate)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出 [2, 4, 6, 8, 10]
1.2.2 map()
- 作用:对流中的每个元素应用给定的函数,生成一个新的流。
- 签名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
List<String> words = Arrays.asList("hello", "world", "java");
List<String> upperCaseWords = words.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperCaseWords); // 输出 [HELLO, WORLD, JAVA]
1.2.3 flatMap()
- 作用:将流中的元素转换成另一个流,然后将多个流合并为一个流。通常用于处理包含集合或数组的流。
- 签名:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("A", "B", "C"),
Arrays.asList("D", "E", "F")
);
List<String> flatList = listOfLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flatList); // 输出 [A, B, C, D, E, F]
1.2.4 distinct()
- 作用:去重,返回一个只包含不同元素的流。
- 签名:
Stream<T> distinct()
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(distinctNumbers); // 输出 [1, 2, 3, 4, 5]
1.2.5 sorted()
- 作用:对流中的元素进行排序。
- 签名:
Stream<T> sorted()
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出 [1, 2, 3, 5, 8]
比较器
1. comparing
根据属性创建比较器。
ListString sortedByLength = Arrays.asList("apple", "banana", "kiwi").stream().sorted(Comparator.comparing(String::length)).collect(Collectors.toList());
2. naturalOrder
自然顺序比较器。
ListInteger sortedNatural = Arrays.asList(3, 1, 4).stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
3. reverseOrder
逆序比较器。
ListInteger sortedReverse = Arrays.asList(3, 1, 4).stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
4. thenComparing
添加次要比较规则。
ListString sortedByLengthThenAlphabet = Arrays.asList("apple", "kiwi", "banana").stream().sorted(Comparator.comparing(String::length).thenComparing(Comparator.naturalOrder())).collect(Collectors.toList());
5. reversed
逆序当前比较器。
ListString sortedReverseByLength = Arrays.asList("apple", "kiwi", "banana").stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
// 使用 Lambda 表达式排序 (o1, o2) -> o1 - o2
List<Integer> sortedNumbers = numbers.stream()
.sorted((o1, o2) -> o1 - o2)
.collect(Collectors.toList());
表达式 | 排序顺序 | 逻辑 |
---|---|---|
(o1, o2) -> o1 - o2 | 升序 | 如果 o1 < o2 ,返回负数,o1 排在前面;如果 o1 > o2 ,返回正数,o1 排在后面。 |
(o1, o2) -> o2 - o1 | 降序 | 如果 o2 < o1 ,返回负数,o1 排在前面;如果 o2 > o1 ,返回正数,o1 排在后面。 |
1.2.6 anyMatch(), allMatch(), noneMatch()
-
作用:这些方法用于匹配流中的元素:
anyMatch()
检查流中是否至少有一个元素满足条件。allMatch()
检查流中的所有元素是否都满足条件。noneMatch()
检查流中是否没有元素满足条件。
-
签名:
boolean anyMatch(Predicate<? super T> predicate)
boolean allMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super T> predicate)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyGreaterThan3 = numbers.stream().anyMatch(n -> n > 3); // true
boolean allGreaterThan0 = numbers.stream().allMatch(n -> n > 0); // true
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0); // true
System.out.println(anyGreaterThan3); // 输出 true
System.out.println(allGreaterThan0); // 输出 true
System.out.println(noneNegative); // 输出 true
1.2.7 peek()
- 作用:
peek()
用于在中间操作中查看流中的每个元素。通常用于调试。 - 签名:
Stream<T> peek(Consumer<? super T> action)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream()
.peek(n -> System.out.println("Before filter: " + n))
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
1.3 终止操作
终止操作会触发流的处理,并生成一个最终的结果或副作用。常见的终止操作包括 collect()
, forEach()
, reduce()
, count()
, min()
等。
1.3.1 collect()
- 作用:将流转换为集合或其他类型的结果。
- 签名:
<R, A> R collect(Collector<? super T, A, R> collector)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出 [2, 4]
1.3.2 forEach()
- 作用:对流中的每个元素执行给定的操作。
- 签名:
void forEach(Consumer<? super T> action)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.forEach(n -> System.out.println(n)); // 输出 1, 2, 3, 4, 5
1.3.3 reduce()
- 作用:将流中的元素结合成一个单一的结果,常用于求和、求积等操作。
- 签名:
T reduce(T identity, BinaryOperator<T> accumulator)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println(sum); // 输出 15
1.3.4 count()
- 作用:计算流中的元素个数。
- 签名:
long count()
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.stream()
.filter(n -> n % 2 == 0)
.count();
System.out.println(count); // 输出 2
1.3.5 min() 和 max()
- 作用:找到流中的最小值或最大值。
- 签名:
Optional<T> min(Comparator<? super T> comparator)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> min = numbers.stream()
.min(Integer::compare);
System.out.println(min.get()); // 输出 1
1.3.6 findFirst() 和 findAny()
- 作用:这两个方法用于获取流中的元素。
findFirst()
返回第一个元素。findAny()
返回任意元素(并行流时表现不同)。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> first = numbers.stream().findFirst();
Optional<Integer> any = numbers.stream().findAny();
System.out.println(first.get()); // 输出 1
System.out.println(any.get()); // 输出 任意一个数
总结
- Stream 提供了更简洁、声明式的方式处理数据流。
- 中间操作如
filter()
,map()
,flatMap()
等支持链式操作,实现强大的数据处理能力。 - 终止操作则触发最终的处理过程,如
collect()
,forEach()
,reduce()
等。
2. Optional 类
背景
Optional
是 Java 8 引入的一个容器类,用于解决传统 null
引用带来的 NullPointerException
问题。它表示一个可能为 null
的值,而不是直接使用 null
,通过提供多种方法使得 Optional
的值可以更安全地处理。
Optional
主要用于以下几种场景:
- 避免
null
值:避免直接返回或传递null
,提高代码的可读性和安全性。 - 链式操作:允许对可能为
null
的值进行安全的链式调用,而不必担心NullPointerException
。
2.1 创建 Optional
2.1.1 Optional.of()
- 作用:创建一个非空的
Optional
,如果值为null
,则抛出NullPointerException
。 - 签名:
static <T> Optional<T> of(T value)
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.get()); // 输出 Hello
- 注意:传入
null
会抛出异常。
Optional<String> optional = Optional.of(null); // 会抛出 NullPointerException
2.1.2 Optional.ofNullable()
- 作用:创建一个
Optional
,如果值为null
,则返回一个空的Optional
。 - 签名:
static <T> Optional<T> ofNullable(T value)
Optional<String> optional = Optional.ofNullable("Hello");
System.out.println(optional.get()); // 输出 Hello
Optional<String> emptyOptional = Optional.ofNullable(null);
System.out.println(emptyOptional.isPresent()); // 输出 false
2.1.3 Optional.empty()
- 作用:创建一个空的
Optional
对象。 - 签名:
static <T> Optional<T> empty()
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.isPresent()); // 输出 false
2.2 常用方法
2.2.1 isPresent()
- 作用:检查
Optional
是否包含一个非空的值。 - 签名:
boolean isPresent()
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.isPresent()); // 输出 true
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.isPresent()); // 输出 false
2.2.2 ifPresent()
- 作用:如果
Optional
中有值,则执行给定的操作;如果没有值,则什么也不做。 - 签名:
void ifPresent(Consumer<? super T> action)
Optional<String> optional = Optional.of("Hello");
optional.ifPresent(System.out::println); // 输出 Hello
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(System.out::println); // 不输出任何内容
2.2.3 get()
- 作用:获取
Optional
中的值,如果值不存在,会抛出NoSuchElementException
。 - 签名:
T get()
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.get()); // 输出 Hello
Optional<String> emptyOptional = Optional.empty();
// emptyOptional.get(); // 会抛出 NoSuchElementException
2.2.4 orElse()
- 作用:如果
Optional
中有值,返回该值;如果没有值,返回提供的默认值。 - 签名:
T orElse(T other)
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.orElse("Default Value")); // 输出 Hello
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElse("Default Value")); // 输出 Default Value
2.2.5 orElseGet()
- 作用:与
orElse()
类似,但orElseGet()
使用Supplier
提供默认值,这样可以延迟计算。 - 签名:
T orElseGet(Supplier<? extends T> supplier)
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.orElseGet(() -> "Default Value")); // 输出 Hello
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseGet(() -> "Default Value")); // 输出 Default Value
2.2.6 orElseThrow()
- 作用:如果
Optional
中有值,返回该值;如果没有值,抛出指定的异常。 - 签名:
T orElseThrow(Supplier<? extends X> exceptionSupplier)
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.orElseThrow(() -> new IllegalArgumentException("Value is missing"))); // 输出 Hello
Optional<String> emptyOptional = Optional.empty();
// emptyOptional.orElseThrow(() -> new IllegalArgumentException("Value is missing")); // 会抛出 IllegalArgumentException
2.2.7 map()
- 作用:如果
Optional
中有值,应用给定的映射函数返回一个新的Optional
,如果没有值,则返回一个空的Optional
。 - 签名:
<U> Optional<U> map(Function<? super T, ? extends U> mapper)
Optional<String> optional = Optional.of("Hello");
Optional<String> upperCaseOptional = optional.map(String::toUpperCase);
System.out.println(upperCaseOptional.get()); // 输出 HELLO
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.map(String::toUpperCase).isPresent()); // 输出 false
2.2.8 flatMap()
- 作用:类似于
map()
,但flatMap()
返回的是一个Optional
。通常用于处理返回值本身可能为Optional
的情况。 - 签名:
<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
Optional<String> optional = Optional.of("Hello");
Optional<String> result = optional.flatMap(value -> Optional.of(value.toUpperCase()));
System.out.println(result.get()); // 输出 HELLO
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.flatMap(value -> Optional.of(value.toUpperCase())).isPresent()); // 输出 false
2.2.9 filter()
- 作用:如果
Optional
中有值并且满足给定的条件,则返回一个包含该值的Optional
,否则返回一个空的Optional
。 - 签名:
Optional<T> filter(Predicate<? super T> predicate)
Optional<Integer> optional = Optional.of(5);
Optional<Integer> result = optional.filter(n -> n > 3);
System.out.println(result.get()); // 输出 5
Optional<Integer> result2 = optional.filter(n -> n < 3);
System.out.println(result2.isPresent()); // 输出 false
2.2.10 ifPresentOrElse()
- 作用:如果
Optional
中有值,执行给定的操作,否则执行提供的另一个操作。 - 签名:
void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
Optional<String> optional = Optional.of("Hello");
optional.ifPresentOrElse(
value -> System.out.println("Value: " + value), // 输出 Value: Hello
() -> System.out.println("Value is absent")
);
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresentOrElse(
value -> System.out.println("Value: " + value),
() -> System.out.println("Value is absent") // 输出 Value is absent
);
2.3 使用场景
2.3.1 使用 Optional
返回可能为 null
的值
在方法中返回 Optional
而非直接返回 null
,避免客户端代码中直接进行 null
值检查。
public Optional<String> findUserById(int userId) {
User user = userRepository.findById(userId);
return Optional.ofNullable(user != null ? user.getName() : null);
}
Optional<String> name = findUserById(1);
name.ifPresent(System.out::println); // 如果值存在,打印用户名
2.3.2 使用 Optional
简化链式调用
Optional
可以避免 null
检查,并通过 map()
、flatMap()
、filter()
等方法方便地进行链式调用。
public Optional<Address> getUserAddress(User user) {
return Optional.ofNullable(user)
.map(User::getAddress);
}
Optional<Address> address = getUserAddress(user);
address.ifPresent(addr -> System.out.println("Address: " + addr.getStreet()));
总结
Optional
提供了一种优雅的方式来处理可能为null
的值,避免了NullPointerException
。- 常用方法如
map()
、filter()
、ifPresent()
、orElse()
、orElseThrow()
等,使得对Optional
的操作更加简洁且安全。 - 使用
Optional
可以有效提高代码的可读性和可维护性,尤其是在返回可能为null
的值时。
通过理解和使用 Optional
,可以显著降低出现空指针异常的风险,优化代码的健壮性。
是的,Stream
和 Optional
是两个不同的类,但它们在 Java 8 及之后的版本中被设计成可以很方便地结合使用。让我们更详细地探讨一下这两个类如何协同工作,以及它们如何互相配合以简化代码、提高可读性和健壮性。
3.Stream
和 Optional
关系
1. Stream
和 Optional
的基本区别
-
Stream
是一个用于处理集合数据的接口。它代表了一系列的元素,支持函数式操作(如过滤、映射、排序等)。Stream
操作通常返回一个新的流对象,而不是修改原始数据源。示例:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); stream.filter(x -> x > 2).forEach(System.out::println); // 输出: 3, 4, 5
-
Optional
是一个容器对象,表示值的存在与否。它用于避免NullPointerException
,并通过Optional
中的函数方法,提供更优雅的null
值处理方式。Optional
可以包含一个值,也可以是空的(即Optional.empty()
)。示例:
Optional<String> name = Optional.ofNullable("John"); name.ifPresent(System.out::println); // 输出: John
2. 如何结合使用 Stream
和 Optional
虽然 Stream
和 Optional
的作用不同,但它们在实际编程中有很多交集。主要的原因是 Stream
中的某些操作返回的是 Optional
,而 Optional
也提供了一些函数式方法,使得它可以链式地进行操作,和 Stream
很好地结合。
2.1. Stream
操作返回 Optional
某些 Stream
方法在无法返回单一元素时会返回 Optional
。例如,findFirst()
、findAny()
、reduce()
等方法:
// 返回一个包含第一个匹配元素的 Optional,如果流为空,则返回 Optional.empty()
Optional<String> firstMatch = Stream.of("apple", "banana", "cherry")
.filter(fruit -> fruit.startsWith("b"))
.findFirst();
// 输出:Optional[banana]
System.out.println(firstMatch);
2.2. Optional
的方法可以与 Stream
配合使用
-
Optional
提供了一些方法(如map()
、flatMap()
、filter()
、ifPresent()
等)可以在值存在时进行链式操作。通过这些方法,你可以对流中的元素进行转换、过滤等操作,并优雅地处理null
情况。例如,可以将
Stream
中的元素通过findFirst()
查找后,进行Optional
操作:
String result = Stream.of("apple", "banana", "cherry")
.filter(fruit -> fruit.startsWith("b"))
.findFirst() // 返回 Optional<String>
.map(String::toUpperCase) // Optional -> Optional<String>
.orElse("No match found");
System.out.println(result); // 输出: BANANA
这里,我们使用 findFirst()
返回一个 Optional
,然后使用 map()
方法将值转换为大写。如果 findFirst()
找不到任何匹配的元素,则使用 orElse()
给出一个默认值 "No match found"
。
3. Stream
与 Optional
的常见组合方式
以下是 Stream
和 Optional
常见的组合方式,展示了如何利用这两者的结合处理数据。
3.1. findFirst()
与 map()
findFirst()
返回一个 Optional
,如果有匹配的元素就返回该元素,否则返回 Optional.empty()
。结合 map()
,可以在找到了元素后进行转换:
Optional<String> firstMatch = Stream.of("apple", "banana", "cherry")
.filter(fruit -> fruit.startsWith("b"))
.findFirst();
String result = firstMatch
.map(String::toUpperCase)
.orElse("No match found");
System.out.println(result); // 输出: BANANA
3.2. filter()
和 flatMap()
Optional
提供了 filter()
和 flatMap()
方法,这使得你可以更灵活地进行操作。例如,filter()
用于基于条件过滤,而 flatMap()
可以将 Optional
转换为另一个 Optional
,从而支持链式操作。
Optional<String> firstMatch = Stream.of("apple", "banana", "cherry")
.filter(fruit -> fruit.startsWith("b"))
.findFirst();
String result = firstMatch
.filter(fruit -> fruit.length() > 5) // 过滤掉长度小于等于5的水果
.map(String::toUpperCase)
.orElse("No match found");
System.out.println(result); // 输出: BANANA
3.3. reduce()
和 Optional
reduce()
是 Stream
中常用的一个方法,它将流中的元素聚合为一个单一的结果。reduce()
返回的类型是 Optional
,因为结果可能为空。
Optional<Integer> sum = Stream.of(1, 2, 3, 4, 5)
.reduce(Integer::sum);
sum.ifPresent(System.out::println); // 输出: 15
4. 小结
Stream
用于处理数据流,可以对集合中的数据进行函数式操作,支持各种中间操作(如filter()
、map()
、flatMap()
等)。Optional
用于处理可能为null
的值,避免显式的null
检查,它提供了方便的函数式方法(如map()
、orElse()
、filter()
等)。Stream
中的某些方法(如findFirst()
、reduce()
)返回Optional
,使得它可以与Optional
紧密结合,利用Optional
的函数式方法优雅地处理流中的元素。
通过这种方式,Stream
和 Optional
可以非常自然地协作,避免了传统的 null
检查,使得代码更加简洁和易于维护。
🎉🌈 陪伴至此,感谢有你 🌈🎉
感谢你能坚持看到这里!如果这篇文章对你有一点点帮助,希望能收获你的:
👍 一个赞,⭐ 一个收藏,💬 一条评论 或 🔗 一键分享!
你的支持是我持续输出的最大动力!✨有问题?有灵感?
别犹豫,直接留言和我交流~让我们一起成长、一起突破 💡。最后,祝你:
🍯 生活美满如蜜香
🌞 心情灿烂似朝阳
🌱 成长如树渐成章
🚀 未来闪耀梦飞翔!再次感谢你的阅读!🌟 下次再见~ 🎉