一回顾与说明

经过前面发布的三章java8的博客,你就懂得了我们为什么要用Lamda表达式,Lamda表达式的原理与函数式接口的关系,从Lamda表达式到方法引用和构造引用。

想要学Stream流你必须对前面的知识熟悉并且掌握,今天我们来讲一下Lamda表达式的进阶学习,Stream流API。

二什么是Stream流

流想比大家都认识,比如食物的包装过程,先要有个食物员提供食物,食物经过加工处理,添加调料,...,包装,组装。简单的说普通的流就像工厂的流水线一样。

Stream流是可以能够用声明的方式来操作集合(可以想象sql操作数据库那样),可以将其看作遍历数据集的高级迭代器。在操作流的时候我们就可以将其比喻成工厂中的流水线。

三 流的优势

流有什么优势呢?流竟然是一种迭代器,那它与集合的for循环有什么区别,为什么我们要用流来迭代呢?

  • 集合中存放的数据都是计算好的,我们用一次集合遍历,必须有始有终,不能中断。Stream流像视频流一样我们可以先加载一部分,看一部分,中途还能暂停中断离开;相比之集合流更加灵活
  • 流的迭代遍历是一次性的,意味着一个流你只能迭代一次,完成迭代这个流就被消费掉。
  • 流相比于for循环是内部迭代的,我们只要给出具体的函数操作流就ok,而for循环是外部迭代。

四 Stream流的操作过程

Stream流跟生产线上的流类式有提供源,操作,终止三个过程



常见的中间操作流:



常见的结束流:​

五常见的StreamAPI

初始化车辆信息

    public List<Car> InitCar(){
ArrayList<Car> 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<Car> cars = carFunFactory.InitCar();
// 筛选车辆时黑色的车
List<Car> 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<Car> 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<Car> 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<Car> 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<Car> 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<Car> cars = carFunFactory.InitCar();
// 不是youku1327这个颜色的车
Optional<Car> 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<Car> cars = carFunFactory.InitCar();
// 不是youku1327这个颜色的车
Optional<Car> 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<Long> 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<Integer> 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<String> 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<String> 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操作基本就可以胜任平常工作中的各种场景,后面会继续更新流的高级操作

最后推一波微信公众号,有兴趣学习的就关注吧。

java8-Stream流API的更多相关文章

  1. Java8 Stream流API常用操作

    Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...

  2. 【JDK8】Java8 Stream流API常用操作

    Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...

  3. 【转】Java8 Stream 流详解

      当我第一次阅读 Java8 中的 Stream API 时,说实话,我非常困惑,因为它的名字听起来与 Java I0 框架中的 InputStream 和 OutputStream 非常类似.但是 ...

  4. Java8 Stream流

    第三章 Stream流 <Java8 Stream编码实战>的代码全部在https://github.com/yu-linfeng/BlogRepositories/tree/master ...

  5. 关于Java8 Stream流的利与弊 Java初学者,大神勿喷

    题目需求: 1:第一个队伍只要名字为3个字成员的姓名,存储到新集合 2:第一个队伍筛选之后只要前3人:存储到一个新集合 3:第2个队伍只要姓张的成员姓名:存储到一个新集合 4:第2个队伍不要前2人,存 ...

  6. Java8——Stream流式操作的一点小总结

    我发现,自从我学了Stream流式操作之后,工作中使用到的频率还是挺高的,因为stream配合着lambda表达式或者双冒号(::)使用真的是优雅到了极致!今天就简单分(搬)享(运)一下我对strea ...

  7. Java9系列第6篇-Stream流API的增强

    我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...

  8. Java8 Stream流方法

    流是Java API的新成员,它允许以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现).就现在来说,可以把它们看成遍历数据集的高级迭代器.此外,流还可以透明地并行处理,无需写任何多 ...

  9. Java8 - Stream流:让你的集合变得更简单!

    前段时间,在公司熟悉新代码,发现好多都是新代码,全是 Java8语法,之前没有了解过,一直在专研技术的深度,却忘了最初的语法,所以,今天总结下Stream ,算是一份自己理解,不会很深入,就讲讲常用的 ...

  10. java8 stream 流 例子

    Trader raoul = new Trader("Raoul", "Cambridge"); Trader mario = new Trader(" ...

随机推荐

  1. zip的压缩和解压命令

    以下命令均在/home目录下操作cd /home #进入/home目录 1.把/home目录下面的data目录压缩为data.zip zip -r data.zip data #压缩data目录   ...

  2. Spring中常见的设计模式——单例模式

    一.单例模式的应用场景 单例模式(singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点.J2EE中的ServletContext,ServletCon ...

  3. day 27 网路编程 面向对象多继承

    知识补充: 字符串转化为字节 string1  = input(“请输入你的名字”) string1.encode('utf-8') 字节转化为字符串 byte1 = b"alex" ...

  4. c#-PropertyChangingEventArgs

    MSDN 解释连接:https://msdn.microsoft.com/zh-cn/library/system.eventargs.aspx#inheritanceContinued[Serial ...

  5. IdentityServer4 自定义授权模式

    IdentityServer4除了提供常规的几种授权模式外(AuthorizationCode.ClientCredentials.Password.RefreshToken.DeviceCode), ...

  6. LESSON 2-Discrete Source Encoding

    Keywords: Source types, Discrete source coding, Kraft inequality 1.      Source classes About Figure ...

  7. Incorrect string value: '\xF0\x9F\x92\x8BTi...'错误

    一.背景 1.java项目,name含有表情插入到mysql数据库中报错   Incorrect string value: '\xF0\x9F\x92\x8BTi.. 2.解决办法 (1)将字符串中 ...

  8. Android Binder机制介绍

    做过Android开发的同学可能有些体会,入门初期,工作内容主要是实现各式各样的UI界面,以及实现应用的业务逻辑.在这个阶段,我们会逐渐熟悉View系统,逐渐学会实现各种各样的界面以及动画效果.再往后 ...

  9. java静态初始化块(静态域)

    1. 类变量的初始化可通过静态初始化块来进行. 代码放在一对大括号内,大括号前用static修饰:static {……} 一个类可定义1个或多个静态初始化块. 静态初始化块会在加载时调用而且只被调用一 ...

  10. OCR文字识别在计算机视觉的重要性、基本技术和最新进展

    [摘要] 主要是文字检测和文字识别作为计算机视觉一部分的重要性,基本知识,面临的挑战,以及部分最新的成果. 人类认识了解世界的信息中91%来自视觉,同样计算机视觉成为机器认知世界的基础,也是人工智能研 ...