一回顾与说明
经过前面发布的三章java8的博客,你就懂得了我们为什么要用Lamda表达式,Lamda表达式的原理与函数式接口的关系,从Lamda表达式到方法引用和构造引用。
想要学Stream流你必须对前面的知识熟悉并且掌握,今天我们来讲一下Lamda表达式的进阶学习,Stream流API。
二什么是Stream流
流想比大家都认识,比如食物的包装过程,先要有个食物员提供食物,食物经过加工处理,添加调料,...,包装,组装。简单的说普通的流就像工厂的流水线一样。
Stream流是可以能够用声明的方式来操作集合(可以想象sql操作数据库那样),可以将其看作遍历数据集的高级迭代器。在操作流的时候我们就可以将其比喻成工厂中的流水线。
三 流的优势
流有什么优势呢?流竟然是一种迭代器,那它与集合的for循环有什么区别,为什么我们要用流来迭代呢?
- 集合中存放的数据都是计算好的,我们用一次集合遍历,必须有始有终,不能中断。Stream流像视频流一样我们可以先加载一部分,看一部分,中途还能暂停中断离开;相比之集合流更加灵活
- 流的迭代遍历是一次性的,意味着一个流你只能迭代一次,完成迭代这个流就被消费掉。
- 流相比于for循环是内部迭代的,我们只要给出具体的函数操作流就ok,而for循环是外部迭代。
四 Stream流的操作过程
Stream流跟生产线上的流类式有提供源,操作,终止三个过程
常见的中间操作流:
常见的结束流:
五常见的StreamAPI
初始化车辆信息
public List InitCar(){
ArrayList carList = new ArrayList<>();
Car car1 = new Car("100", "black", "中国", 20);
Car car2 = new Car("101", "gray", "中国", 30);
Car car3 = new Car("102", "yello", "中国", 50);
Car car4 = new Car("103", "silvery", "英国", 20);
Car car5 = new Car("104", "red", "英国", 30);
carList.add(car1);
carList.add(car2);
carList.add(car3);
carList.add(car4);
carList.add(car5);
return carList;
}
1 筛选
filter函数就是过滤出流中我们需要的元素--中间操作
@Test
public void filterTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 筛选车辆时黑色的车
List result = cars.stream()
.filter(car -> car.getColor().equals("black"))
.collect(Collectors.toList());
//[Car(code=100, color=black, factory=中国, price=20.0)]
System.out.println(result);
}
2排序
sorted函数默认会升序排序元素--中间操纵
@Test
public void sortTest(){
int[] ints = {0, 5, 7, 6, 15, 13, 27};
Arrays.stream(ints).sorted().forEach(System.out::println);
}
3 去重
distinct去掉重复的元素--中间操作
@Test
public void distinctTest(){
int[] ints = {5,6,5,6,27};
// 5 6 27
Arrays.stream(ints).distinct().forEach(System.out::println);
}
4 截断
limit函数限值流的元素--中间操作
@Test
public void limitTest(){
int[] ints = {5,6,5,6,27};
// 5 6
Arrays.stream(ints).limit(2).forEach(System.out::println);
}
5跳跃
skip函数跳过n个元素--中间操作
@Test
public void skipTest(){
int[] ints = {5,6,5,6,27};
// 27
Arrays.stream(ints).skip(4).forEach(System.out::println);
}
6映射
map是转换函数,接受一个函数为参数,将其映射在每一个元素上,转换成新的元素。--中间操作
@Test
public void mapTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 只获得车的价格
cars.stream().limit(1)
.map(Car::getPrice)
.forEach(System.out::println);//20.0
}
7流的扁平化
flatMap函数能将中间多个流的内容合并为一个流。--中间操作
@Test
public void flatMapTest(){
String[] array = {"youku1327"};
// 存放的是一个个数组 [Ljava.lang.String;@61f3fbb8
Arrays.stream(array).map(s -> s.split(""))
.forEach(System.out::print);
// 将一个个数组流合并为一个流输出:youku1327
Arrays.stream(array).map(s -> s.split(""))
.flatMap(Arrays::stream)
.forEach(System.out::print);
}
8任意匹配
anyMatch函数任意匹配到流中的一个元素返回真。---终止操作
@Test
public void anyMatchTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 任意匹配黄色的车
boolean yello = cars.stream()
.anyMatch(car -> car.getColor().equals("yello"));
System.out.println(yello);//true
}
9 完全匹配
allMatch函数完全匹配流中的元素返回真。--终止操作
@Test
public void allMatchTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 完全匹配黄色的车
boolean yello = cars.stream()
.allMatch(car -> car.getColor().equals("yello"));
System.out.println(yello);//false
}
10非匹配
noneMatch函数没有匹配到流中的任意一个元素返回为真。------终止操作
@Test
public void noneMatchTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 不是youku1327这个颜色的车
boolean yello = cars.stream()
.noneMatch(car -> car.getColor().equals("youku1327"));
System.out.println(yello);//true
}
11任意寻找流中的一个元素
findAny函数任意查找流中的一个元素返回。---终止操作
@Test
public void findAnyTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 不是youku1327这个颜色的车
Optional anyCar = cars.stream().findAny();
Car car = anyCar.orElse(new Car("141", 50));
// Car(code=100, color=black, factory=中国, price=20.0)
System.out.println(car);
}
12 寻找流中的第一个元素
findFirst函数寻找流中的第一个元素。--------终止操作
@Test
public void findFirstTest(){
// 初始化车辆
List cars = carFunFactory.InitCar();
// 不是youku1327这个颜色的车
Optional anyCar = cars.stream().findFirst();
// Car(code=100, color=black, factory=中国, price=20.0)
System.out.println(anyCar.get());
}
13 归约
reduce函数将前一个入参数和后一个入参进行操作后的值做为第下一次操作的前一个入参,以此类推。--终止操作
@Test
public void reduceTest(){
int[] ints = {3,4,5,};
int reduce = Arrays.stream(ints)
.reduce(0, (left, right) -> left + right);
// 求和 12
System.out.println(reduce);
OptionalInt max = Arrays.stream(ints).reduce(Integer::max);
// 求最大值 5
System.out.println(max.getAsInt());
OptionalInt min = Arrays.stream(ints).reduce(Integer::min);
// 求最小值 3
System.out.println(min.getAsInt());
}
14数值流
IntStream 、 DoubleStream 和LongStream ,分别将流中的元素特化为 int 、 long 和 double ,避免自动装箱
。-----中间操作
@Test
public void numTest(){
int[] ints = {5,6,5,6};
// int流
IntStream intStream = Arrays.stream(ints);
// 6767爱看youku1327
intStream.mapToObj(value -> value+1).forEach(System.out::print);
System.out.println("爱看youku1327");
double[] doubles = {5,6,5,6};
// double流
DoubleStream doubleStream = Arrays.stream(doubles);
//5.06.05.06.0关注youku1327
doubleStream.forEach(System.out::print);
System.out.println("关注youku1327");
// long流
Long[] longs = {5L,6L,5L,6L};
Stream longStream = Arrays.stream(longs);
long count = longStream.count();
// 4
System.out.println(count);
}
15 流转换
boxed函数将数值流转为原始流。-----中间操作
@Test
public void streamSwapTest(){
int[] ints = {5,6,7};
// 将int流转为原始流
Optional first = Arrays.stream(ints).boxed().findFirst();
System.out.println(first.get());//5
// 2.23606797749979 2.449489742783178 2.6457513110645907
Arrays.stream(ints).boxed()
.mapToDouble(s ->Math.sqrt(s))
.forEach(System.out::println);
}
六 构建流
1 数值生成流
@Test
public void buildStreamByValue(){
Stream stream = Stream.of("关", "注", "微", "信", "公", "众", "号", ":", "youku1327", "谢谢");
//关注微信公众号:youku1327谢谢
stream.map(StringUtils::join).forEach(System.out::print);
}
2 由数组创建流
@Test
public void skipTest(){
int[] ints = {5,6,5,6,27};
// 27
Arrays.stream(ints).skip(4).forEach(System.out::println);
}
3 由文件创建流
@Test
public void buildStreamByFile(){
try {
Stream lines = Files.lines(Paths.get("C:\\mydata\\youku1327.txt"), Charset.defaultCharset());
lines.map(s -> s.split(""))
.flatMap(Arrays::stream)
.forEach(System.out::print);//youku1327
} catch (IOException e) {
e.printStackTrace();
}
}
4创建无限流
generate和iterate都是创建无限流,我们要约束一下,以免无线流一直创建元素。
@Test
public void buildStreamByIterate(){
long count = Stream.iterate(1, integer -> integer + 1)
.limit(100)
.count();
System.out.println(count);//100
}
七 致谢
观看完这一篇stream流API操作基本就可以胜任平常工作中的各种场景,后面会继续更新流的高级操作
最后推一波微信公众号,有兴趣学习的就关注吧。