当前位置: 首页 > news >正文

Java函数式编程之【Stream终止操作】【上】【简单约简】

函数式编程可分为三个步骤:Stream(流)的创建、Stream的中间操作和Stream的终止操作。其中Stream(流)的中间操作可以有n个,而Stream(流)的终止操作只能有一个。

函数式编程三个步骤示意图:
在这里插入图片描述
函数式编程步骤三:Stream(流)的终止(Terminal)操作,又称终端操作。
Stream(流)的终止(Terminal)操作是Stream API中的关键概念,终止操作它会触发整个流操作管道的计算,并收集计算结果。终止操作的方法繁多,终止操作都是主动求值操作。我们把Stream的终止操作大致分为三大类:简单约简操作、简单的终止操作和复杂终止操作。
(一)、八个常用的简单约简终止操作

  • allMatch、anyMatch、noneMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为boolean值。
  • count 统计操作,统计最终的数据个数(长整型long)。
  • findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional<T>
  • min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值,类型为Optional<T>

简单约简的返回结果的数据类型除了count()是长整型long外,其他都是booleanOptional<T> 类型。

(二)、五个简单的终止操作

  • forEach 遍历操作,对Stream中的数据元素进行消费操作。
  • forEachOrdered 遍历操作,并行流时对Stream中的数据元素进行消费操作,使保持原始顺序。
  • toArray 数组操作,将Stream中的数据元素存放到数组中。
  • toArray(IntFunction<A[]>)数组操作,将A[]::new参数传给构造器,返回A类型的数组。
  • Iterator iterator() 迭代操作,将Stream中的数据元素存放到迭代中,以便进行复杂的处理。

(三)、复杂的终止操作

  • reduce 归约操作,将整个Stream中的数据元素归约为一个值,例如:count、min、max底层就是使用reduce实现的。
  • collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说终止操作collect是Stream的终极大杀器。

本文主要介绍简单约简操作、简单的终止操作。

一、八个常用的简单约简终止操作的使用示例

1,其中三个终止操作可归属为匹配操作(allMatch、anyMatch、noneMatch)。Stream也支持类似集合匹配元素的操作,其匹配返回的结果的数据类型是boolean类型。
这三个匹配操作的方法签名如下:

	//allMatch(Predicate): Stream中所有元素都匹配时返回true。方法签名是:boolean allMatch(Predicate<? super T> predicate)//anyMatch(Predicate): Stream中任意元素匹配时返回true。方法签名是:boolean anyMatch(Predicate<? super T> predicate)//noneMatch(Predicate): Stream中没有元素匹配时返回true。方法签名是:boolean noneMatch(Predicate<? super T> predicate)

先请看几个简单示例:

	List<Integer> list = Arrays.asList(7, 6, 9, 3, 2, 15);boolean resultAny = list.stream().anyMatch(x -> x < 6);boolean resultAll  = list.stream().allMatch(x -> x < 6);boolean resultNone  = list.stream().noneMatch(x -> x < 6);

2,统计操作 count(): 统计Stream中元素的数量。其方法签名:

	//count(): 统计Stream中的元素个数。方法签名是:long count()

简单示例:

	long num = Stream.of("Alice", "Bob", "Charlie").count();

3,计算最大和最小值:max(Comparator) 和 min(Comparator): 根据比较器返回Stream中的最大或最小元素,返回的类型为Optional<T>。其方法签名:

	//max(Comparator): 返回Stream中元素的最大值,需要指定比较器,方法签名是:Optional<T> max(Comparator<? super T> comparator)//min(Comparator): 返回Stream中元素的最小值,需要指定比较器,方法签名是:Optional<T> min(Comparator<? super T> comparator)

实际上,终止操作max()和min()都是reduce操作,其底层都是由reduce()实现的,将他们单独设为函数只是因为常用。
Java 8的max()方法的具体实现在java\util\stream\ReferencePipeline类中,它是reduce()方法的一个特例。请看终止操作max()的源代码:

    @Overridepublic final Optional<P_OUT> max(Comparator<? super P_OUT> comparator) {return reduce(BinaryOperator.maxBy(comparator));}	//max()的实现代码。

在这里插入图片描述

使用示例:

		Optional<String> maxName = Stream.of("Alice", "Bob", "Charlie").max(Comparator.naturalOrder());System.out.println("最长的名字:" + maxName.get());List<String> sList = Arrays.asList("World", "me", "you");Optional<String> min = sList.stream().min(Comparator.comparing(String::length));System.out.println("最短的字符串:" + min.get());Optional<String> max = sList.stream().max(Comparator.comparing(String::length));System.out.println("最长的字符串:" + max.get());

4,查找操作:(findFirst/findAny)查找第一个、查找任何一个 返回的类型为Optional<T>。其方法签名是:

	//findAny(): 返回任意元素。方法签名是:Optional<T> findAny()//findFirst(): 返回第一个元素。方法签名是:Optional<T> findFirst()

使用示例:

        List<Integer> list = Arrays.asList(7, 6, 9, 3, 2, 15);// 匹配第一个Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();// 匹配任意(适用于并行流)Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();System.out.println("匹配第一个值:" + findFirst.get());System.out.println("匹配任意一个值:" + findAny.get());  

请看一个综合应用示例:
【例程10-16】 八种简单约简终止操作演示例程StreamTerminal
例程用到一个自定义的test.Student类,Student.java其源码如下:

package test;
import java.util.Objects;
public class Student {public enum Status { FREE,BUSY }private String name = "未登记"; //默认值private Integer age =17; //默认值private Integer score = 60; //默认值private Status status =Status.FREE; //默认值public Student() { }public Student(String n) {	name = n; }public Student(String n, Integer a) {name = n;age = a;}public Student(String n, Integer a,Integer s) {name = n;        age = a;score = s;}public Student(String n, Integer a,Integer s, Status status) {this(n, a, s);this.status = status;}public String getSLevel()  //得到成绩级别 { return (score>80) ? "优秀" : (score<60) ? "不及格" : "普通" ; }public String getName() { return name; }public void setName(String name) { this.name = name; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }public Integer getScore() { return score; }public void setScore(Integer score) { this.score = score; }public Status getStatus() { return status; }public void setStatus(Status status) { this.status = status; }@Overridepublic boolean equals(Object o) {if (o==null ) return false;if (this==o) return true;if (getClass()!=o.getClass()) return false;Student student = (Student)o;boolean result = Objects.equals(name, student.name);result = result&&Objects.equals(age, student.age);return result&&Objects.equals(score, student.score);}@Overridepublic int hashCode() {int result = name.isEmpty() ? 0 : name.hashCode();result = 31*result + (age==null ? 0 : age.hashCode());return 31*result + (score==null ? 0 : score.hashCode());}@Overridepublic String toString() {return "Student {"+"name="+name+",\tage="+age+",\tscore="+score+"}";}
}		//类Student.java定义结束。

八种简单约简操作的示例程序StreamTerminal.java,在例程中我们为每一种约简操作定义了一个测试方法:

package test;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import test.Student.Status;
/**** @author QiuGen* @description  八种简单约简终止操作演示例程StreamTerminal* @date 2024/6/14* ***/
public class StreamTerminal {public final static List<Student> students = Arrays.asList(new Student("Mary", 16, 85, Status.BUSY),new Student("Hellon", 18, 45),new Student("John", 17, 60),new Student("Karl", 17, 90, Status.BUSY),new Student("Bob", 18, 75, Status.BUSY),new Student("Tony", 16, 55));public static void allMatchTest(int age) {boolean b=students.stream().allMatch(s->s.getAge()>age);System.out.printf("年龄>%d   allMatch结果:%b%n",age,b);}	public static void anyMatchTest(int age) {boolean b=students.stream().anyMatch(s->s.getAge()>age);System.out.printf("年龄>%d   anyMatch结果:%b%n",age,b);}	public static void noneMatchTest(int score) {boolean b=students.stream().noneMatch(s->s.getScore()>score);System.out.printf("成绩>%d   noneMatch结果:%b%n",score,b);}public static void findFirstTest() {Optional<Student> sOpnal =students.stream().filter(s->s.getStatus().equals(Status.BUSY)).findFirst();if (sOpnal.isPresent()) System.out.println("findFirst:"+sOpnal.get());}public static void findAnyTest() {Optional<Student> sOpnal =students.stream().filter(s->s.getStatus().equals(Status.BUSY)).findAny();if (sOpnal.isPresent()) System.out.println("findAny:"+sOpnal.get());}public static void countTest() {long count =students.stream().filter(s->s.getStatus().equals(Status.BUSY)).count();System.out.println("BUSY状态统计结果:"+count);}public static void maxTest() {Optional<Student> sOpnal =students.stream().filter(s->s.getStatus().equals(Student.Status.BUSY)).max(Comparator.comparingInt(Student::getScore));if (sOpnal.isPresent()) System.out.println("BUSY状态最高分:"+sOpnal.get());}public static void minTest() {Optional<Student> sOpnal =students.stream().filter(s->s.getStatus().equals(Student.Status.FREE)).min((a,b)->a.getAge()-b.getAge()); //比较年龄if (sOpnal.isPresent()) System.out.println("FREE状态最低年龄:"+sOpnal.get());}public static void main(String[] args) {int age = 17,  score = 70;allMatchTest(age);anyMatchTest(age);noneMatchTest(score);noneMatchTest(90);findFirstTest();findAnyTest();countTest();maxTest();minTest();}
}		//例程结束。例程StreamTerminal.java结束。

再来看一个实际应用示例:
【例程10-17】 并行流实现质数的计算和统计例程ParallelCountPrimes
利用并行流和allMatch()终止操作实现“质数的计算和统计”例程:

package stream;	
import java.util.stream.IntStream;
/**** @author QiuGen* @description  并行流的质数计算和统计例程ParallelCountPrimes* @date 2024/8/16* ***/
public class ParallelCountPrimes {private static boolean isPrime(int number) {return IntStream.range(2, number).allMatch(x -> (number % x) != 0);}public static long countPrimes(int upTo) {return IntStream.range(2, upTo).parallel().filter(ParallelCountPrimes::isPrime).peek(System.out::println).count();}	public static void main(String[] args) {int limit = 100;long count = ParallelCountPrimes.countPrimes(limit);System.out.println("100以内的素数共有:"+count);}
}

二、五个简单的终止操作使用示例
五个简单的终止操作的方法签名:

//forEach(Consumer): 按指定的消费者处理器方法对每个元素进行处理,但不能保证按流中的顺序处理元素,方法签名是:
void forEach(Consumer<? super T> action)
//forEachOrdered(Consumer): 与forEach(Consumer)的不相同之处在于,该方法可确保按流中的顺序处理元素,常用于并行流。方法签名是:
void forEachOrdered(Consumer<? super T> action)
//toArray(): 产生一个对象数组。方法签名是:
Object[] toArray()
//toArray(IntFunction<A[]>): 将A[]::new参数传给构造器,返回A类型的数组。方法签名是: 
<A> A[] toArray(IntFunction<A[]> generator)
//iterator(): 这是BaseStream类的方法。产生一个获取当前流中元素的迭代器。其方法签名是:
Iterator<T> iterator()

五个简单的终止操作使用示例:
【例程10-18】利用toArray()终止操作收集斐波那契数列的例程
迭代生成斐波那契数列的long[]无限流,用toArray收集结果

package stream;
import java.util.stream.Stream;
/**** @author QiuGen* @description  迭代生成斐波那契数列的long[]无限流,然后再用toArray()收集结果的例程FibStreamToArray* @date 2024/8/16* ***/
public class FibStreamToArray {public static void fibStreamToArray() {long[] array = Stream.iterate(new long[]{0, 1},fib -> new long[]{fib[1], fib[0] + fib[1]}).map(fib -> fib[0]).limit(30)   //前30项.mapToLong(Long::longValue).toArray();for (int n = 0; n < array.length; n++) {System.out.println(array[n]);}} public static void main(String[] args) {fibStreamToArray();}
}

下面的例程用整型数的对象流和String的对象流分别演示用toArray()收集结果到数组,各用了两种收集方式。请自行思考这两种收集方式的不同之处。
【例程10-19】几个简单的利用toArray()收集结果到数组的示例StreamTerminalToArray

package stream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamTerminalToArray {public static void toArrayTest() { //收集到数组toArray()/***整型数的对象流***/int [] a = Stream.of(1, 2, 3, 4).mapToInt(Integer::intValue).toArray();int [] b = IntStream.of(1, 2, 3, 4).toArray();/***字符串的对象流***/List<String> strList = Arrays.asList("Ok", "welcom", "good");Object[] objs = strList.stream().toArray(); //收集到Object数组for (int i = 0; i < objs.length; i++) {System.out.println(objs[i]);}System.out.println("------------------------");String[] words = strList.stream().toArray(String[]::new);for (int i = 0; i < words.length; i++) System.out.println(words[i]);/*** 使用示例:Object[] objMen = personStream().filter(p->p.getGender() == MALE).toArray();Person[] men = personStream().filter(p->p.getGender() == MALE).toArray(Person[]::new);***/}public static void main(String[] args) {toArrayTest();}
}

【例程10-20】迭代器iterate()终止操作的演示例程
由于本例要用到Student类,及需要一些数据准备工作,我们在前文例程StreamTerminal.java基础上,增加一个静态方法来演示迭代器(iterate)终止操作:

public static void iterateTerminalTest() {  	//iterateTerminalTest()方法源码开始:Iterator<Integer> iter = Stream.iterate(0, n->n+1).limit(8).iterator();while (iter.hasNext())  System.out.println(iter.next());Iterator<Double> iter2 = Stream.generate(Math::random).limit(6).iterator();while (iter2.hasNext()) {System.out.println("浮点数:" + (Double) iter2.next() );}Iterator<Student> iterator = students.stream().filter(s->s.getAge()>16).filter(s->s.getStatus()==Status.BUSY).iterator();while (iterator.hasNext()) {Student s = (Student) iterator.next();System.out.printf("Name: %s  Status: %s  age= %d score=%d%n",
s.getName(),s.getStatus(),s.getAge(),s.getScore());}
}	//迭代器iterate()终止操作的演示例程:iterateTerminalTest()方法源码结束。
http://www.dtcms.com/a/313072.html

相关文章:

  • ethtool,lspci,iperf工具常用命令总结
  • 前端面试手撕题目全解析
  • CXGrId中按回车控制
  • 微店所有店铺内的商品数据API接口
  • 宝马集团与SAP联合打造生产物流数字化新标杆
  • 达梦数据库备份与还原终极指南:从基础到增量策略实战
  • [leetcode] 位运算
  • 【网络与爬虫 39】Crawlee现代爬虫革命:TypeScript驱动的智能数据采集框架
  • 井盖识别数据集-2,700张图片 道路巡检 智能城市
  • C的运算符与表达式
  • iNavFlight飞控固件学习-4《LED初始化》
  • MVCC的实现原理
  • git配置公钥/密钥
  • Android XR SDK深度解析:构建下一代沉浸式体验的开发指南
  • 《从原理到实践:MySQL索引优化与SQL性能调优全解析》
  • Vue中:deep()和 ::v-deep选择器的区别
  • JavaScript:编程世界中的“语盲”现象
  • Java,八股,cv,算法——双非研0四修之路day24
  • ulimit参数使用详细总结
  • ELECTRICAL靶机
  • Transformer模型用于MT信号相关性预测与分析
  • python的易物小店交换系统
  • 2106. 摘水果
  • 数据结构中使用到的C语言
  • RocksDb 是什么?levelDB、LSM 树、SSTable又分别是什么?区别呢?
  • Linux 内存调优之如何限制进程、系统级别内存资源
  • 第二章 矩阵
  • 剥离petalinux设备树,使用 dtc 单独编译
  • 主流身份认证协议都有哪些?应用场景有何区别?
  • BRL贝叶斯规则列表