Stream流
前言:
流式编程:流式编程是一种编程范式。
Stream流是依附Lambda表达式。Stream API 是与 Lambda 表达式紧密相关的。在 Java 8 中引入了 Lambda 表达式的同时,也引入了 Stream API。Lambda 表达式提供了一种简洁的方式来传递行为,而 Stream API 则提供了一种流畅的、函数式的方式来处理集合数据。
在Java中,一元操作符是一种操作符,只涉及一个操作数。Java提供了多种一元操作符,用于执行各种操作。
操作符及功能:
-
递增和递减操作符:
++
:递增操作符,用于将操作数的值增加1。--
:递减操作符,用于将操作数的值减少1。
-
正负号操作符:
+
:正号操作符,用于表示正数。在实际应用中并不经常使用,因为正号没有实际改变数值。-
:负号操作符,用于表示负数。
-
逻辑非操作符:
!
:逻辑非操作符,用于将布尔值取反。如果操作数为true,则结果为false;如果操作数为false,则结果为true。
-
按位取反操作符:
~
:按位取反操作符,用于按位取反操作数的二进制表示。例如,~x
会对x的每个二进制位取反。
-
类型转换操作符:
(type)
:用于执行强制类型转换。例如,(int) x
将变量x强制转换为int类型。
这些一元操作符可以应用于各种数据类型,包括整数、浮点数和布尔值。在Java中,一元操作符可以用于变量、常量或表达式中。
1. 流式思想
流式思想类似于工厂车间的”流水线“。当需要对元素进行操作(特别是多部操作)时,考虑到性能机便利性,应该先拼好一个”模型步骤方案“,然后再用方案执行。
类比到编程,流式思想也是一种将处理过程划分为一系列步骤的方式。每个步骤都执行特定的操作,然后将结果传递给下个步骤进行进一步处理。
这种方式使得代码更具可读性和可维护性。同时每个步骤都可重用,从而提高代码的灵活性和效率。
2. Stream(流)的概念
Stream是JDK1.8中处理集合的关键抽象概念。Stream提供一种新的方式来处理集合数据,是代码更为简介,易懂,高效。
使用Stream API 对集合数据进行操作,类似于使用SQL执行数据库查询。
Stream处理元素可以看作是一种流式处理。元素流在管道中经过中间操作的处理,由终端操作得到前面处理的结果。
特点:
-
连续的数据序列: Stream流代表了一系列元素的连续流,这些元素可以来自集合、数组、I/O通道等数据源。它们提供了一种更便捷和抽象的方式来处理数据集合。
-
惰性求值: Stream流的操作是惰性求值的,这意味着流的操作不会立即执行,直到需要结果时才会进行计算。这种延迟执行的特性使得流操作非常高效,尤其是在处理大数据集时。
-
函数式编程风格: Stream流提供了一套丰富的函数式编程风格的操作方法,例如map、filter、reduce、collect等。这些方法允许通过函数式接口来对流中的元素进行转换、过滤、聚合等操作,使得代码更加简洁和灵活。
-
流水线操作: Stream流的操作可以被连接成一个流水线,其中每个操作依次应用于流中的每个元素。这种流水线操作的设计使得代码更易读、易于理解,并且可以轻松地进行操作的组合和重用。
-
中间操作和终端操作: Stream操作可以分为中间操作和终端操作两种类型。中间操作(Intermediate Operations)用于对流中的元素进行转换、筛选等操作,而终端操作(Terminal Operations)则产生最终的结果。终端操作是流的触发点,执行终端操作后流将被消费,无法再进行其他操作。
3. Stream 创建
1) 通过集合创建
方法一:使用集合类提供的stream()方法获取一个串行流;
方法二:使用parallelStream()方法获取一个并行流,以提高处理效率。(用于多线程安全高效情况下)
// 1. 通过集合创建 List<String> listStream = Arrays.asList("张三","李四","王五"); // 创建包含字符串元素的列表 Stream<String> sequentialStream = listStream.stream(); // 串行流 Stream<String> parallelStream = listStream.parallelStream(); // 并行流
串行流是 Stream API 中的一种流,它按照元素在集合中的顺序进行处理,即一个元素处理完成后才会处理下一个元素。
并行流是 Stream API 中的一种流,它会将数据分成多个小块并行处理,以提高处理效率。
2) 通过数组创建
使用Arrays类的静态方法stream()获取数组的流。
// 2. 通过数组创建 String[] array = {"赵六","孙七","周八"}; // 创建包含字符串元素的数组 Stream<String> stream = Arrays.stream(array); // 调用 Arrays 类的 stream() 方法,将数组 array 转换为一个 Stream 流 stream;
3) 通过Stream内的静态方法创建
使用Stream.of()方法可直接创建一个包含指定元素的流。
// 3. 通过Stream内的静态方法创建 Stream<String> streamStatic = Stream.of("曹阿瞒","刘玄德","孙仲谋");
4) 创建无限流
无限流是指流中的元素数量是无限的,因此需要采取一些方式来限制流的大小,以便在实际处理中不会造成无限处理的情况。
流中元素无限多,配合limit()使用。
方式一:使用Stream.iterate()方法创建无限流
Stream.iterate()方法接受一个初始值和一个一元操作符(UnaryOperator)作为参数。会从初始值开始,通过一元操作符生成后续的元素。
// 4. 创建无限流 // 方式一: // 例:使用 Stream.iterate(0, n -> n + 2) 来创建一个从0开始,每次加2的无限流。 /** * 调用Stream的iterate()方法创建创建流。 * 两个参数:第一个参数为初始值:0;第二个参数用Lambda表达式表示对当前元素 n+2,生成下一个。 */ Stream<Integer> iterate = Stream.iterate(0,n -> n + 2); // 使用limit()方法来限制打印数量 iterate.limit(10).forEach(System.out::println); // 结果:0, 2, 4, 6, 8, ... // 例:使用 Stream.iterate() 方法从初始值 1 开始,每次将前一个元素乘以 2 生成后续的元素 // 使用 limit(10) 方法限制了流的大小为 10 个元素,collect(Collectors.toList())是 Java 8 中 Stream API 中的一个方法调用,最终将这些元素收集到一个列表中。 List<Integer> iterateCollection = Stream.iterate(1, n -> n*2).limit(10).collect(Collectors.toList()); System.out.println("iterateCollection = " + iterateCollection); // 结果:iterateCollection = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
一元操作符是一种操作符,只涉及一个操作数。Java提供了多种一元操作符,用于执行各种操作。
方法二:使用Stream.generate()方法来创建无限流
Stream.geberate()方法接受一个Supplier函数式接口作为参数,该接口生成流中的元素。因Supplier作为一个生产者,所以可产生无限的元素。
// 方式二: // 例:使用 Stream.generate(Math::random) 来创建一个包含随机数的无限流。 Stream<Double> generate = Stream.generate(Math::random); // 调用 Stream 类的静态方法 generate() 来创建流。接受一个参数: Stream<Double> 函数式接口。 generate.limit(10).forEach(System.out::println); // 结果随机十条,范围在 0.0 到 1.0 之间。 // 例:使用 Stream.generate() 创建一个无限流,元素是随机的整数 // () -> new Random().nextInt(100) 作为 Supplier,每次调用它都会生成一个 0 到 99 之间的随机整数。 List<Integer> generateCollection = Stream.generate(() -> new Random().nextInt(100)).limit(10).collect(Collectors.toList()); System.out.println("generateCollection = " + generateCollection); // 结果:generateCollection = [66, 48, 82, 43, 84, 67, 28, 72, 18, 21]
当创建流时,如果数组中包含基本数据类型的元素,而我们希望将其转换为对应的引用数据类型,需要使用 boxed()
方法进行装箱操作。
// 当创建流时,如果数组中包含基本数据类型的元素,而我们希望将其转换为对应的引用数据类型,需要使用 boxed() 方法进行装箱操作。 double[] arrays = {2024.0221, 25, 19, 9.12}; DoubleStream doubleStream = Arrays.stream(arrays); // Arrays.stream(arrays) 方法将基本数据类型的double数组转换为DoubleStream流; Stream<Double> boxed = doubleStream.boxed(); // 通过boxed 方法,将DoubleStream流内的元素装箱为Stream<Double>, 即可在流内操作引用数据类型。
4. Stream流的中间操作
Stream流的中间操作指的是,在处理String类型的流时,可以对流内的数据进行一系列的中间操作,以实现特定的处理需求。
这些中间操作不会立即触发流的需求,而是返回一个新的流,这样可以构成一条流水线,最终可以通过终端处理流。
常见的Stream API流的中间操作:
- filter(Predicate):filter()方法根据指定的条件过滤流中的元素,只保留满足条件的元素,丢弃不满足条件的元素。
- map(Function):map()方法将流内的每个元素映射为另一个元素,通过给定的函数。可以对流中的元素进行转换或提取重要的元素。
- flatMap(Function):flatMap()方法将流中的每个元素映射为一个流,将所有的流连接为一个流。常用于将多个流合并为一个流,将流中的元素扁平化处理。或将流中的每个元素拆分为多个元素。
- distinct():distinct()方法用于去除流中的重复元素,返回一个取出后的新流。
- sorted():sorted()方法用于对流中的方法进行排序,返回一个新的流。默认按自然顺序排序,也可传入自定义的Comparator来制定排序规则。
- limit(long):limit()方法用于限制流中元素的数量,返回一个包含前n个元素的新流。
- skip(long):skip()方法用于跳过流中的前n个元素,返回一个新流。
1) filter需要的参数为Predicate--判断。Predicate中的test()方法的参数就是流中的数据类型。
// 1. filter // 例:使用 filter() 方法来过滤一个整数流,只保留偶数。 // 创建一些包含整数的流。IntStream.rangeClosed() 是 Java 中的一个静态方法调用,用于创建一个包含指定范围内整数的 IntStream 流。 IntStream intStream = IntStream.rangeClosed(0,10); // 生成从1-10的整数流 // 使用filter()方法过滤出整数 IntStream evenStream = intStream.filter(n -> n % 2 == 0); // 打印过滤后的结果 evenStream.forEach(System.out::println); // 结果:0,2,
2) limit()
- 用于限制流内元素的数量。指定的参数表示要保留的元素的数量;
- 参数为0时,表示不获取任何元素,返回一个空流;
- 参数为正整数时,表示从流中获取前几个元素;
- 参数不可为负,否则会抛出异常;
- limit()方法常和无限流配合使用,用于限制流的大小,使其变为有限流;
// 2. limit // 例:使用 Stream.generate() 方法生成一个无限流,每次生成一个 0 到 99 之间的随机整数。 // 使用 limit(8) 方法来限制流中元素的数量为8个,并通过 forEach(System.out::println) 方法将这8个元素打印出来。 Stream.generate(() -> new Random().nextInt(100)).limit(8).forEach(System.out::println);
3) skip()
skip方法与limit()方法相反,用于跳过流内的前几个元素,然后返回一个新的流。
skip()方法接受一个long类型的参数,表示要跳过的元素数量。
// 3. skip // 例:使用 skip() 方法跳过流中的前几个元素 // 创建一个包含一些整数的流 Stream<Integer> skipStream = Stream.iterate(1, n -> n + 1); // 创建一个无限流,从1开始递增 // 使用skip方法从第三个元素开始,跳过4个元素,然后继续获取4条 skipStream.limit(3) // 显示3条 .forEach(System.out::println); // 注意:skipStream 在上面第一次使用后已经被消耗掉了,不能再使用。 skipStream = Stream.iterate(1, n -> n +1); // 重新创建一个新的流 skipStream.skip(3 + 4) // 跳过前3条,再跳过4条 .limit(4) // 获取四条 .forEach(System.out::println); // 打印结果:1,2,3 8,9,10,11
注意:流是一次性资源,一旦被消耗就无法再次使用。
4) distinct()
用于去除流内重复数据,返回一个去重后的新流。如果流内元素为引用数据类型,需重写equals()和hashCode();
因为 distinct()
方法在去除重复元素时,会依赖对象的 equals()
和 hashCode()
方法来确定元素是否相等。如果这两个方法没有正确重写,可能会导致 distinct()
方法无法准确识别和去除重复元素。
// 4. distinct // 例:创建了一个包含一些字符串的流 stringStream,其中包含了一些重复的元素。 // 使用 distinct() 方法对流中的元素进行去重,返回一个新的流 distinctStream。 // 通过 forEach(System.out::println) 方法将去重后的结果打印出来。 Stream<String> nonReferenceDataTypeStream = Stream.of("张三","李四","王五","赵六","赵六","李四","赵六"); // 使用distinct()方法去除重复元素 Stream<String> distinctStream = nonReferenceDataTypeStream.distinct(); distinctStream.forEach(System.out::println);
为引用数据类型时:
// Person类,在流内去除重复的Person对象 // 重写了 equals() 和 hashCode() 方法,确保在比较两个 Person 对象时,它们的 name,age,sex 都相等时才被认为是相等的。 public class Person { private String name; private Integer age; private String sex; public Person(String name, Integer age, String sex) { this.name = name; this.age = age; this.sex = sex; } // 重写equals方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(name, person.name) && Objects.equals(age, person.age) && Objects.equals(sex, person.sex); } // 重写hashCode方法 @Override public int hashCode() { return Objects.hash(name, age, sex); } // 重写toString方法 @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; } }
// 例:创建一个包含一些 Person 对象的流 personStream,其中有一些重复的对象。 // 使用 distinct() 方法对流中的 Person 对象进行去重,并将去重后的结果打印出来。 Stream<Person> personStream = Stream.of( new Person("张三",20,"男"), new Person("李四",23,"女"), new Person("王五",26,"男"), new Person("李四",23,"女"), new Person("赵六",24,"女") ); // 使用 distinct()方法去除重复的Person对象 Stream<Person> deduplicationPerson = personStream.distinct(); deduplicationPerson.forEach(System.out::println); // 打印结果:李四保留一条
5) sort()
对流内的元素进行排序。
可按照自然元素和指定的指定器来排序元素,并返回一个新的流。其中包含排序后的元素序列。
自然排序(从小到大):
// 5. sort() // 创建了一个包含一些整数的列表 numbers,然后使用 numbers.stream() 方法将列表转换为流。 // 使用 sorted() 方法对流中的元素进行排序,这里是按照自然顺序(从小到大)排序的。 // 通过 collect(Collectors.toList()) 方法将排序后的结果收集到一个列表中,并打印出来。 // 创建一个包含一些整数的列表 List<Integer> numbers = Arrays.asList(7,88,32,22,25,18,45); // 使用sort()方法对列表内的元素进行排序 List<Integer> sortNumbers = numbers.stream().sorted() // 按默认自然顺序排 .collect(Collectors.toList()); System.out.println("倒序" + numbers.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList())); // 倒叙 System.out.println("自然排序后的结果:" + sortNumbers); // 打印结果:自然排序后的结果:[7, 18, 22, 25, 32, 45, 88]
自定义比较器:Comparator。
// 自定义比较器:Comparator。比较器将字符串按照长度从小到大进行排序 // 创建了一个包含一些字符串的列表 names,然后使用 names.stream() 方法将列表转换为流。 // 使用 sorted() 方法并传入一个自定义的比较器 Comparator.comparingInt(String::length),该比较器将字符串按照长度从小到大进行排序。 // 通过 collect(Collectors.toList()) 方法将排序后的结果收集到一个列表中,并打印出来。 // 创建包含一些字符串的列表 List<String> names = Arrays.asList("jiaWenHe","sunQuan","caoMengDe","liuBei"); // 使用sort()方法对列表内的字符串进行长度排序 List<String> sortNames = names.stream() .sorted(Comparator.comparingInt(String::length)) // 比较器将字符串按照长度从小到大进行排序 .collect(Collectors.toList()); // 将排序后的结果收集到列表内 sortNames.forEach(System.out::println);
6) map()
映射。接受一个函数作为参数,函数将流内每个元素(数据类型)转换(映射)为另一个元素(数据类型),并返回一个新的流,并包含映射后的元素序列。map()的映射参数为Function。
// 6. map() // 创建了一个包含一些整数的列表 numbersMap,然后使用 numbersMap.stream() 方法将列表转换为流。 // 使用 map() 方法并传入一个 lambda 表达式 n -> n * n,该表达式将流中的每个元素转换为其平方。 // 通过 collect(Collectors.toList()) 方法将转换后的结果收集到一个列表中,并打印出来。 // 创建包含整数的列表 List<Integer> numbersMap = Arrays.asList(1,2,3,4,5); // 使用map()方法将列表内的元素转化为平方 List<Integer> squaredNumbers = numbersMap.stream() .map(n -> n * n) // 将每个元素转换为其平方 .collect(Collectors.toList()); System.out.println("转换后的结果为:" + squaredNumbers); // 结果打印:转换后的结果为:[1, 4, 9, 16, 25]
7) flatMap()
flatMap()
方法接受一个函数作为参数,这个函数将流中的每个元素映射为一个流,然后将这些流连接成一个单独的流。通常,这个函数的返回值是一个流。
// 7. flatMap() // 有一个嵌套的列表 numbersFlatMap,其中每个列表包含一些整数。 // 使用 flatMap() 方法将嵌套列表中的每个列表转换为一个流,然后将这些流连接成一个单独的流。 // 通过 collect(Collectors.toList()) 方法将连接后的结果收集到一个列表中,并打印出来。 List<List<Integer>> numbersFlatMap = Arrays.asList( Arrays.asList(1,3,5), Arrays.asList(2,4,6), Arrays.asList(8,9,7) ); // 使用flatMap() 将嵌套列表内所有元素连成一个表 List<Integer> flattenedNumbers = numbersFlatMap.stream() .flatMap(List::stream) // 将嵌套列表内的每个列表转为一个,并将他们连接成一个单独的流 .collect(Collectors.toList()); System.out.println("扁平化后的结果:" + flattenedNumbers); // 打印结果:扁平化后的结果:[1, 3, 5, 2, 4, 6, 8, 9, 7]
5. Stream流的终端操作
Stream流的终端操作是在对流进行一系列中间操作后,触发对流的最终处理,从而产生最终结果的操作。
终端操作会触发流的遍历,执行中间操作,并返回最终的结果。流的中间操作是流的“触发器”,没有终端操作,中间操作是不会执行的。
常见的Stream流的终端操作:
allMatch(Predicate):检查流中所有元素是否都满足给定的条件。
anyMatch(Predicate):检查流中是否至少存在一个元素满足给定的条件。
noneMatch(Predicate):检查流中是否没有元素满足给定的条件。
findFirst:返回流内第一个元素。
findAny:返回流内任意元素。
count:返回流中的元素数量。
max(Comparator):返回流内最大元素。
min(Comparator):返回流内最小元素。
forEach(Consumer):对流内的每个元素执行指定的操作。
int[] array = {8, 4, 1, 15, 42, 21, 33}; Stream<Integer> integerStream = Arrays.stream(array).boxed(); // 原始类型数组转换为一个包含相同元素的Stream<Integer>对象 // 1. 流的终端操作-->allMatch() // Predicate 判断 数组内的元素是否都是偶数 System.out.println(integerStream.allMatch(num -> num % 2 == 0)); // 输出:false // 注意:流是一次性的,一旦终端操作触发,流就会被消耗掉,不可再次使用 // 使用新流进行操作 // 2. 流的终端操作-->anyMatch() integerStream = Arrays.stream(array).boxed(); // Predicate 判断数组内是否有任意元素为偶数 System.out.println(integerStream.anyMatch(num -> num % 2 == 0)); // 结果:true // 3. 流的终端操作-->noneMatch() // 使用新流 integerStream = Arrays.stream(array).boxed(); // Predicate 判断组内是否不存在元素为偶数 System.out.println(integerStream.noneMatch(num -> num % 2 == 0)); // 结果:false // 4. 流的终端操作 --> findFirst() // 使用新流 integerStream = Arrays.stream(array).boxed(); // 获取组内大于7的元素,并取第一个元素 Optional<Integer> first = integerStream.filter(num -> num > 7).findFirst(); System.out.println(first.get()); // 结果:8 // 5. 流的终端操作 --> findAny() // 使用新流 integerStream = Arrays.stream(array).boxed(); // 获取组内大于7的元素,并任意取一 Optional<Integer> any = integerStream.filter(num -> num > 8).findAny(); // System.out.println(any.get()); // 结果总会是第一个 >8 的元素; any.ifPresent(System.out::println); // 这是因为:默认串行流,在单线程的情况下,会找到流中的第一个符合条件的元素。 // 6. 流的终端操作 --> count() integerStream = Arrays.stream(array).boxed(); // 计算组内元素的数量 long count = integerStream.count(); System.out.println("count = " + count); // 7. 流的终端操作 --> max() integerStream = Arrays.stream(array).boxed(); // 获取数组内最大的元素 Optional<Integer> max = integerStream.max(Integer::compareTo); // Integer::compareTo 是一个比较器,用于比较两个整数的大小 System.out.println(max.get()); // 8. 流的终端操作操作 --> min() integerStream = Arrays.stream(array).boxed(); // 获取数组内最小的元素 Optional<Integer> min = integerStream.min(Integer::compareTo); System.out.println(min.get()); // 9. forEach() integerStream = Arrays.stream(array).boxed(); // 遍历每个元素 integerStream.forEach(System.out::println);
collect(Collector):将流内的元素搜集到一个结果容器。如:list-列表、set-集、map-映射。
// 10. collect() // 创建Stream流 Stream<Integer> stream = Stream.of(2024, 2021, 2020, 2019); // collect方法收集流内元素 List<Integer> list = stream.collect(Collectors.toList()); // 收集为:list System.out.println(list); // 结果:[2024, 2021, 2020, 2019] stream = Stream.of(2024, 2021, 2020, 2019); Set<Integer> set = stream.collect(Collectors.toSet()); // 收集为Set System.out.println(set); // 结果:[2019, 2020, 2021, 2024] stream = Stream.of(2024, 2021, 2020, 2019); Map<Integer,String> map = stream.collect(Collectors.toMap(x -> x, x -> "value:" + x)); // 收集为map x -> x为生成键,x -> "value:" + x为生成对应值; System.out.println(map); // 结果:{2019=value:2019, 2020=value:2020, 2021=value:2021, 2024=value:2024}
reduce(BinaryOperator):最流内的元素进行归约操作返回一个包含归约结果的Optional对象。元素累计,一般用于加法计算。
// 11. reduce-归约 // 使用reduce方法对流内元素进行求和 Stream<Integer> reduceStream = Stream.of(2024, 2021, 2020, 2019); Integer reduce = reduceStream.reduce(0, (a, b) -> a + b); // 初始值为0,规约操作是将上一侧归约结果与流内下一个元素相加,得和 System.out.println(reduce); // 结果:8084
groupingBy(分组):是一个收集器,用于将流内元素按照指定分类函数进行分组,并将分组结果存储与Map内。通常用于对于流内元素进行分组统计。
// 12. groupingBy() // 根据元素的奇偶性对流中的元素进行分组统计 integerStream = Arrays.stream(array).boxed(); // 将数组转换为流,然后进行封装,封装为Integer类型的对象 Map<String, List<Integer>> group = integerStream.collect(Collectors.groupingBy(x -> x % 2 == 0 ? "偶数" : "奇数")); System.out.println("group = " + group); // 结果:group = {偶数=[8, 4, 42], 奇数=[1, 15, 21, 33]}
6. Optional
Optional是Java8引入的一个类,为了解决空指针异常问题(NullPointerException),是的代码在处理可能为null得值时更为清晰。
特性与用法:
容器性质:Optional是一个容器类,包含某个个类型的值或仅保存null。可用来表示一个值可能为空或不为空的情况。
Optional.of()
是 Optional
类的一个静态方法,用于创建一个包含指定非空值的 Optional
对象。
存在性检查:isPresent()可以检查Optional内包含值。有值则为true;为空则为false。
安全取值:通过get()方法获取Optional内的值;在使用optional.get()前,先使用i是Present()方法先进行存在性检查,以免抛出异常。
提供默认值:防止空指针异常。orElse()方法是isPerson()方法与get()方法得组合,接受一个参数,用于指定默认值。例:orElse(T other)方法是在Optional容器包含数据时返回容器的数据;若为空,则返回默认的数据。
// orElse() // 如果 optionalName 容器中包含数据(即不为空),则直接返回容器中的数据 "Hello,World!"; Optional<String> optionalName = Optional.of("Hello,World!"); String value = optionalName.orElse("Default Value"); System.out.println("value = " + value); // 返回:value = Hello,World! // 如果 emptyOptional 容器为空,则返回指定的默认值 "Default Value"。 Optional<Object> emptyOptional = Optional.empty(); Object defaultValue = emptyOptional.orElse("Default Value"); System.out.println("defaultValue = " + defaultValue); // 返回:defaultValue = Default Value
Optional示例:有一个函数,用于从数据库中获取用户的年龄。由于数据库操作可能失败或返回空值,我们可以使来处理这种情况。
// 定义一个 UserService 类,其中的 getUserAge() 方法模拟了从数据库中获取用户年龄的操作。 // 如果找到了用户年龄,则返回一个包含该年龄的 OptionalTest 对象;如果用户不存在,则返回一个空的 OptionalTest 对象。 public class UserService { // 模拟从数据库获取用户年龄的操作 public Optional<Integer> getUserAge(String userId) { // 从数据查询用户年龄;若找到,返回Optional对象包含该年龄;反之返回一个空的Optional对象 if(userId.equals("202410007")){ return Optional.of(28); }else { return Optional.empty(); } } public static void main(String[] args) { // OptionalTest:有一个函数,用于从数据库中获取用户的年龄。由于数据库操作可能失败或返回空值,我们可以使用 OptionalTest 来处理这种情况。 UserService userService = new UserService(); String userID = "202410007"; // 获取用户年龄并处理结果 Optional<Integer> userAge = userService.getUserAge(userID); // 若用户年龄存在,则打印用户年龄;否则打印默认消息 if (userAge.isPresent()) { int age = userAge.get(); System.out.println("年龄为:" + age); }else { System.out.println("用户年龄不存在."); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库