Java流式编程详解
文章目录
- 1. 一个流的使用例子
- 2. 流简介
- 3. 流的特点
- 4. 流基本操作
- 4.1 中间操作
- 4.2 终端操作
- 5. 筛选和切片
- 5.1 用谓词筛选
- 5.2 筛选各异的元素
- 5.3 截短流
- 5.4 跳过元素
- 6. 映射
- 6.1 对流中每一个元素应用函数
- 6.2 流的扁平化
- 7. 查找和匹配
- 7.1 检查谓词是否至少匹配一个元素
- 7.2 检查谓词是否匹配所有元素
- 7.3 查找任意元素
- 7.4 查找第一个元素
- 8. 归约
- 8.1 元素求和
- 8.2 最大值和最小值
- 9. 数值流
- 9.1 原始类型流特化
- 9.2 数值范围
- 10. 构建流
- 10.1 由值创建流
- 10.2 由数组创建流
- 10.3 由文件生成流
- 10.4 由函数生成流:创建无限流
1. 一个流的使用例子
场景:现在有一个菜品集合,需要找出菜品中的卡路里小于400的菜品并且按照卡路里多少进行排序
class Dish{String name;int price;int calories;public Dish(String name, int price, int calories) {super();this.name = name;this.price = price;this.calories = calories;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public int getCalories() {return calories;}public void setCalories(int calories) {this.calories = calories;}@Overridepublic String toString() {return "Dish [name=" + name + ", price=" + price + ", calories=" + calories + "]";}}
普通方式的实现:
public class StreamDemo {public static void main(String[] args) {List<Dish> menu=Arrays.asList(new Dish("pork",800),new Dish("beef",700),new Dish("chicken",400),new Dish("french fries",530),new Dish("rice",350),new Dish("fruit",120),new Dish("pizza",550));List<Dish> lowCaloriesDish=new ArrayList<>();for(Dish d:menu){if(d.getCalories()<400)lowCaloriesDish.add(d);}Collections.sort(lowCaloriesDish,new Comparator<Dish>() {@Overridepublic int compare(Dish o1, Dish o2) {return Integer.compare(o1.getCalories(), o2.getCalories());}});for(Dish d:lowCaloriesDish)System.out.println(d.getName()+" "+d.getCalories());}
}
使用流实现:
import java.util.List;
import static java.util.stream.Collectors.toList;
public class StreamDemo {public static void main(String[] args) {List<Dish> menu=Arrays.asList(new Dish("pork",800),new Dish("beef",700),new Dish("chicken",400),new Dish("french fries",530),new Dish("rice",350),new Dish("fruit",120),new Dish("pizza",550));List<String> lowCaloriesDishName=menu.stream().filter(d->d.getCalories()<400).sorted((d1,d2)->d1.getCalories()-d2.getCalories()).map(d->d.getName()).collect(toList());for(String name:lowCaloriesDishName)System.out.println(name);}
}
2. 流简介
流是从支持数据处理操作的源生成的元素序列
- 元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值
- 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源
- 数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等
- 流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大的流水线
- 内部迭代:与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的
3. 流的特点
1. 流只能遍历一次
public class StreamDemo {public static void main(String[] args) {List<String> title=Arrays.asList("Java","Python","Go");Stream<String> s=title.stream();s.forEach(System.out::println);s.forEach(System.out::println);}
}
2. 流使用内部迭代
public class StreamDemo {public static void main(String[] args) {List<Dish> menu=Arrays.asList(new Dish("pork",800),new Dish("beef",700),new Dish("chicken",400),new Dish("french fries",530),new Dish("rice",350),new Dish("fruit",120),new Dish("pizza",550));/** 集合使用外部迭代*/List<String> names=new ArrayList<>();Iterator<Dish> iterator=menu.iterator();while(iterator.hasNext()) {Dish d=iterator.next();names.add(d.getName());}System.out.println(names);/** 流使用内部迭代*/List<String> names2=menu.stream().map(Dish::getName).collect(toList());System.out.println(names2);}
}
4. 流基本操作
4.1 中间操作
List<String> names=menu.stream().filter(d->d.getCalories()>400).map(d->d.getName()).limit(3).collect(toList());System.out.println(names);
代码中的filter、map、limit是中间操作
4.2 终端操作
public static void main(String[] args) {List<Dish> menu=Arrays.asList(new Dish("pork",800),new Dish("beef",700),new Dish("chicken",400),new Dish("french fries",530),new Dish("rice",350),new Dish("fruit",120),new Dish("pizza",550));menu.stream().forEach(System.out::println);}
将流中的数据输出到终端上
5. 筛选和切片
5.1 用谓词筛选
filter:返回一个包括所有符合谓词的元素的流
public static void main(String[] args) {List<Dish> menu=Arrays.asList(new Dish("pork",800,false),new Dish("beef",700,false),new Dish("chicken",400,false),new Dish("french fries",530,false),new Dish("rice",350,false),new Dish("fruit",120,true),new Dish("tomato",200,true));List<Dish> vegetableMenu=menu.stream().filter(d->d.isVegetable)//是否是蔬菜.collect(toList());System.out.println(vegetableMenu);}
5.2 筛选各异的元素
distinct():它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流
List<Integer> numbers=Arrays.asList(1,2,2,3,4,4,5,7);List<Integer> evenNumbers=numbers.stream().filter(x->x%2==0)//寻找偶数.collect(toList());System.out.println(evenNumbers);//[2, 2, 4, 4]
上面代码在一个集合中寻找偶数,结果中有两个相同的2,两个相同的4
List<Integer> numbers=Arrays.asList(1,2,2,3,4,4,5,7);List<Integer> evenNumbers=numbers.stream().filter(x->x%2==0)//寻找偶数.distinct()//distinct保证元素唯一.collect(toList());System.out.println(evenNumbers);//[2, 4]
5.3 截短流
limit(n):该方法会返回一个不超过给定长度的流
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);List<Integer> evenNumbers=numbers.stream().filter(x->x%2==0)//寻找偶数.collect(toList());System.out.println(evenNumbers);//[2, 4, 6, 8]
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);List<Integer> evenNumbers=numbers.stream().filter(x->x%2==0)//寻找偶数.limit(2).collect(toList());System.out.println(evenNumbers);//[2, 4]
5.4 跳过元素
skip方法返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);List<Integer> evenNumbers=numbers.stream().filter(x->x%2==0)//寻找偶数.skip(1)//跳过流中的前n个元素.collect(toList());System.out.println(evenNumbers);//[4, 6, 8]
6. 映射
6.1 对流中每一个元素应用函数
/** 先找出集合中的偶数 再将这些偶数进行平方操作*/List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);List<Integer> evenNumbers=numbers.stream().filter(x->x%2==0)//寻找偶数.map(x->x*x).collect(toList());System.out.println(evenNumbers);//[2,4,6,8]->[4, 16, 36, 64]
6.2 流的扁平化
List<String> words=Arrays.asList("Monday","Tuesday");List<String> characters=words.stream().map(word->word.split(""))//将每个单词转化为一个字符串数组.flatMap(Arrays::stream)//将每个字符数组扁平化.collect(toList());System.out.println(characters);//[M, o, n, d, a, y, T, u, e, s, d, a, y]
7. 查找和匹配
7.1 检查谓词是否至少匹配一个元素
anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词
List<Integer> numbers=Arrays.asList(1,2,4);if(numbers.stream().anyMatch(x->x%2==1)) {System.out.println("numbers集合中至少有1个奇数");}else {System.out.println("numbers集合中没有奇数"); }
7.2 检查谓词是否匹配所有元素
allMatch检查流中的元素是否都能匹配给定的谓词
List<Integer> numbers=Arrays.asList(1,2,3);if(numbers.stream().allMatch(x->x%2==1)) {System.out.println("numbers集合中都是奇数");}else {System.out.println("numbers集合中不全是奇数"); }
7.3 查找任意元素
findAny方法将返回当前流中的任意元素
List<Integer> numbers=Arrays.asList(1,2,3,4,5);Optional<Integer> allEven=numbers.stream().filter(x->x%2==0).findAny();System.out.println(allEven);
7.4 查找第一个元素
List<Integer> numbers=Arrays.asList(1,2,3,4,5);Optional<Integer> firstEven=numbers.stream().filter(x->x%2==0).findFirst();System.out.println(firstEven);//Optional[2]
8. 归约
8.1 元素求和
/** reduce的第一个参数:初始值 相当于给求和一个初值* reduce的第二个参数:一个BinaryOperator<T>来将两个元素结合起来产生一个新值*/List<Integer> numbers=Arrays.asList(4,3,5,9);int sum=numbers.stream().reduce(0, (a,b)->a+b);System.out.println("sum="+sum);//21
8.2 最大值和最小值
/** reduce重载的变体* 它不接受初始值,但是会返回一个Optional对象*/List<Integer> numbers=Arrays.asList(4,3,5,9);Optional<Integer> maxNum=numbers.stream().reduce((x,y)->x>y?x:y);Optional<Integer> minNum=numbers.stream().reduce((x,y)->x<y?x:y);System.out.println("maxNum="+maxNum);//maxNum=Optional[9]System.out.println("minNum="+minNum);//minNum=Optional[3]
9. 数值流
9.1 原始类型流特化
class Goods{String name;int price;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public Goods(String name, int price) {super();this.name = name;this.price = price;}@Overridepublic String toString() {return "Goods [name=" + name + ", price=" + price + "]";}}
1. 映射到数值流
mapToInt返回一个IntStream(而不是一个Stream)
public static void main(String[] args) {List<Goods> goods=Arrays.asList(new Goods("Apple", 10),new Goods("Banana", 5),new Goods("Bread", 3),new Goods("Milk", 15),new Goods("Wine", 20));//将Good对象流映射到价格流(整数流) 并求出价格总和int priceSum=goods.stream().mapToInt(g->g.getPrice()).sum();System.out.println(priceSum);//53}
2.转换回对象流
boxed方法:要把原始流转换成一般流(这里每个int都会装箱成一个Integer)
List<Goods> goods=Arrays.asList(new Goods("Apple", 10),new Goods("Banana", 5),new Goods("Bread", 3),new Goods("Milk", 15),new Goods("Wine", 20));IntStream intStream=goods.stream().mapToInt(g->g.getPrice());Stream<Integer> stream=intStream.boxed();
9.2 数值范围
Java 8引入了两个可以用于IntStream和LongStream的静态方法,帮助生成这种范围:range(左闭右开)和rangeClosed(左闭右闭)
//生成[1,50]内的所有偶数IntStream evenNums=IntStream.rangeClosed(1, 50).filter(x->x%2==0);evenNums.forEach(x->{System.out.print(" "+x);});
10. 构建流
10.1 由值创建流
使用静态方法Stream.of,通过显式值创建一个流
Stream<String> stream=Stream.of("Java","Python","Go");stream.forEach(System.out::println);
10.2 由数组创建流
使用静态方法Arrays.stream从数组创建一个流
int[] numbers= {1,2,3,4,5,6};IntStream stream=Arrays.stream(numbers);stream.forEach(System.out::println);
10.3 由文件生成流
Stream<String> lines=null;try {lines=Files.lines(Paths.get("data.txt"),Charset.defaultCharset()); lines.forEach(System.out::println);} catch (IOException e) {e.printStackTrace();}finally {lines.close();}
10.4 由函数生成流:创建无限流
1. 迭代
/** iterate方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda(UnaryOperator<t>类型)* 这里,我们使用Lambda n-> n+2,返回的是前一个元素加上2*/Stream.iterate(0,n->n+2).limit(10).forEach(System.out::println);
/** 生成斐波那契数列*/Stream.iterate(new int[] {0,1},t->new int[] {t[1],t[0]+t[1]}).limit(10).forEach(t->{System.out.println(t[0]+" "+t[1]);});
2. 生成
/** 生成10个随机数*/Stream.generate(Math::random).limit(10).forEach(System.out::println);
Java流式编程详解相关推荐
- Java-Stream流式编程详解
目录 一.概述 1.1.特性: 不存储数据.不改变数据源.不可重复使用 1.2.生成流的方式 1.3.反转流到集合 二.中间节点与终值节点 2.1.中间节点 2.2.终值节点 三.Stream的方法 ...
- Java stream流式计算详解
Java stream流式计算详解 1. Stream概述 1.1 Stream简介 1.2 Stream分类 2. Stream操作 2.1 Stream创建 2.2 Stream无状态操作 2.3 ...
- Java JUC并发编程详解
Java JUC并发编程详解 1. JUC概述 1.1 JUC简介 1.2 进程与线程 1.2 并发与并行 1.3 用户线程和守护线程 2. Lock接口 2.1 Synchronized 2.2 什 ...
- Java高并发编程详解系列-Java线程入门
根据自己学的知识加上从各个网站上收集的资料分享一下关于java高并发编程的知识点.对于代码示例会以Maven工程的形式分享到个人的GitHub上面. 首先介绍一下这个系列的东西是什么,这个系列自己 ...
- java流式编程(六)Collector接口
目录 一.接口定义 二.接口泛型 一.接口定义 public interface Collector<T, A, R> {Supplier<A> supplier();BiCo ...
- Java高并发编程详解系列-类加载
之前在写关于JVM的时候提到过类加载机制,类加载机制也是在Java面试中被经常问道的一个问题,在这篇博客中就来了解一下关于类加载的知识. 类加载 在JVM执行Java程序的时候实际上执行的编译好的 ...
- flink大数据处理流式计算详解
flink大数据处理 文章目录 flink大数据处理 二.WebUI可视化界面(测试用) 三.Flink部署 3.1 JobManager 3.2 TaskManager 3.3 并行度的调整配置 3 ...
- java socket/Serversocket编程详解(中/英文)
socket /套接字 Sockets let you send raw streams of bytes back and forth between two computers, giving y ...
- Java高并发编程详解系列-线程上下文设计模式及ThreadLocal详解
导语 在之前的分享中提到过一个概念就是线程之间的通信,都知道在线程之间的通信是一件很消耗资源的事情.但是又不得不去做的一件事情.为了保证多线程线程安全就必须进行线程之间的通信,保证每个线程获取到的 ...
最新文章
- 关于Android 构建
- linux cmake 多线程 错误 undefined reference to 'pthread_create'
- respect labor
- p字间距 html段落内文字设置字间距间隔
- 常用的C#正则表达式!
- Java基础学习记录
- python codefirst_Python code.co_consts方法代码示例
- 飞线5根连接图_手机主板焊盘掉点飞线维修方法
- FPGA入门——1位全加器设计
- php扩展 ioncube组件的安装方法_安装IonCube Loader扩展方法
- mysql data seek_mysql_data_seek函数详解
- 视频大数据与物联网(IoT)融合发展的探索
- RTX用户帮助中心群:177262328
- RFID NFC NfcA NfcB NfcF NfcV Ndef NdefFormatable相关详解
- BIgDecimal的用法,及与各类数据类型的转换
- html2Canvas 边框虚线
- 区块链实战(一)实现简单的区块与区块链交易
- k8s pod 无法运行,错误registry.access.redhat.com/rhel7/pod-infrastructure:latest
- FairyGUI学习
- 测试游戏战地1配置软件,《战地1》显卡横向测试:良心真优化
热门文章
- 科学家首次拍到座头鲸交配场景:持续仅30秒
- 福禄克DSX-600测线仪使用手册
- 21款奔驰款奔驰GLC260L升级香氛负离子 告别异味
- C语言:输入10个人的英文(拼音也行)名字,名字按字母顺序从小到大排列.
- 免费赠书 | 房价的一元回归分析
- 全国行政区划代码(json对象)---只包含城市代号和城市名称的json对象代码(包括县级市)
- 多任务进化优化算法(三)利用显式自编码器的进化多任务、基于生物群落共生的进化多任务优化简介
- 蓝牙客户端QBluetoothSocket的使用——Qt For Android
- RT_Thread_临界资源保护
- java-php-python-ssm基于汽车美容管理计算机毕业设计