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

java8函数式编程学习(一):lambada表达式和stream流的使用

简介

jdk8的新特性中的lambada和stream流的简单使用。

函数式编程

优点

  • 代码的可读性更高,更简洁,开发更快速,易于理解
  • 更高效率的处理大数据量的集合

底层使用了并行流,简化了多线程的用法,不用自己去编写复杂的多线程,而是调用函数式编程的方法,可以高效率的处理大数据集合。

思想

和面向对象不同,不用关注哪个对象完成了什么操作,而是关注对数据做了什么操作,类似于数学中的函数。

lambada表达式

可以对某些匿名内部类进行简化,是函数式编程的一个重要体现,让我们不用关注什么是对象,而是关注数据的操作。

格式

(参数)->{代码}

核心原则是:可推导可省略
如果类型可以推导出来,就省略类型,方法名可以推导出来,就省略方法名。

例子一

public class lambadaTest {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("hello,christ");}}).start();//使用lambada表达式编写new Thread(()->{System.out.println("it's too dark");}).start();}
}

省略掉的

new Thread(new Runnable() {@Overridepublic void run() {}}

其实是多余的格式化的代码,类名方法名都是因为Java格式的限制,lambada只关注它的参数和方法体

例子二

package com;import java.util.function.IntBinaryOperator;public class lambadaTest2 {public static void main(String[] args) {int i =calculateNum(new IntBinaryOperator() {@Overridepublic int applyAsInt(int left, int right) {return left + right;}});//使用lambada改造int j =calculateNum((int left, int right)->{return left + right;});System.out.println(i);System.out.println(j);}//IntBinaryOperator是一个接口,里面只有一个方法applyAsIntpublic static int calculateNum(IntBinaryOperator operator){int a = 10;int b = 20;return operator.applyAsInt(a,b);}
}

对于一个匿名内部类,可以在方法名上alt+回车,查看是否可以替换成lambada表达式。
在这里插入图片描述
对于一个lambada表达式,也可以还原成普通的匿名内部类。
在这里插入图片描述

省略规则

  • 参数类型可以省略
  • 方法体只有一句话时,大括号,return,代码后面的分号都可省略
  • 方法只有一个参数时,小括号可以省略

例子二中的代码

        int j =calculateNum((int left, int right)->{return left + right;});

可以省略成

        int j =calculateNum((left,right)->left + right);

Stream流

stream流使用的是函数式编程,可以更方便的对集合或者数组进行链状流式的操作。

例子

创建一个maven项目

pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion>
<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>
</dependencies><groupId>org.example</groupId><artifactId>streamTest</artifactId><version>1.0-SNAPSHOT</version></project>
Author类
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Author {private Long id;private String name;private Integer age;private String intro;private List<Book> books;
}
Book类
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Author {private Long id;private String name;private Integer age;private String intro;private List<Book> books;
}
StreamTest类
package com;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class StreamTest1{public static void main(String[] args) {List<Author> authors  = getAuthors();//使用流操作,打印出年龄大于25的作者,名字去重authors.stream().distinct().filter(author -> author.getAge()>25).forEach(author -> System.out.println(author.getName()));}private static List<Author> getAuthors() {Author author1 = new Author(1L, "作者1", 23, "简介1", null);Author author2 = new Author(2L, "作者2", 24, "简介2", null);Author author3 = new Author(3L, "作者3", 27, "简介3", null);Author author4 = new Author(3L, "作者3", 27, "简介3", null);List<Book> books1 = new ArrayList<>();List<Book> books2 = new ArrayList<>();List<Book> books3 = new ArrayList<>();books1.add(new Book(1L, "书名1", "分类1", 100, "信息1"));books1.add(new Book(2L, "书名2", "分类1", 99, "信息2"));books2.add(new Book(3L, "书名3", "分类2", 98, "信息3"));books2.add(new Book(3L, "书名4", "分类2", 97, "信息4"));books2.add(new Book(4L, "书名5", "分类1,分类2", 96, "信息5"));books3.add(new Book(5L, "书名6", "分类1,分类2", 95, "信息6"));books3.add(new Book(6L, "书名7", "分类3", 94, "信息7"));books3.add(new Book(6L, "书名8", "分类1,分类2,分类3", 93, "信息8"));author1.setBooks(books1);author2.setBooks(books2);author3.setBooks(books3);author4.setBooks(books3);return new ArrayList<>(Arrays.asList(author1, author2, author3,author4));}
}

注意:这个去重distinct是根据author类中的@EqualsAndHashCode去判断的,也就是author4要和author3一模一样,才可以起效,一样的id,一样的书籍著作

输出结果

在这里插入图片描述

idea进行debug

在这里插入图片描述
有专门的stream流工具,可以看到每一步stream流操作的结果。
在这里插入图片描述

常用操作

创建stream流
集合:

集合对象.stream()

package com;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;public class StreamTest4 {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);list.stream().forEach(i-> System.out.println(i));}
}
数组

Arrays.stream(数组对象)
Stream.of(数组对象)

package com;import java.util.stream.Stream;public class StreamTest3 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5,6};Stream.of(arr).forEach(arr3-> System.out.println(arr3));}
}
map集合

先把map集合使用entrySet()方法转换成set对象,然后这个set对象.stream()转换成流对象。

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;public class StreamTest2 {public static void main(String[] args) {Map<String,String> map = new HashMap<>();map.put("one","1");map.put("two","2");map.put("three","3");Set<Map.Entry<String, String>> entries = map.entrySet();entries.stream().forEach(entry-> System.out.println(entry.getKey()+"----"+entry.getValue()));}
}
filter

可以对stream流中的元素进行过滤。

package com;import java.util.stream.Stream;public class StreamTest5 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5,6};Stream.of(arr).filter(arr3->arr3>3).forEach(arr3-> System.out.println(arr3));}
}
map

可以对Stream流中的元素进行计算或转换。
在上面那个author,book的例子中

    public static void main(String[] args) {List<Author> authors  = getAuthors();authors.stream().map(author -> author.getName()).forEach(author-> System.out.println(author));}

在这里插入图片描述
从debug中,可以看到,stream流中的元素已经从author转变为string

使用map进行计算

    public static void main(String[] args) {List<Author> authors  = getAuthors();authors.stream().map(age -> age.getAge()).map(age->age+10).forEach(author-> System.out.println(author));}
distinct

可以去除流中的重复数据,它依赖于object中的equals方法,所以流中的元素的对象要重写equals方法。

package com;
import java.util.stream.Stream;public class StreamTest6 {public static void main(String[] args) {Integer[] arr =  {1,1,2,2,3,3,4,4,5,6};Stream.of(arr).distinct() .forEach(arr3-> System.out.println(arr3));}
}
sorted

可以对stream流中的元素进行排序

import java.util.stream.Stream;public class StreamTest7 {public static void main(String[] args) {Integer[] arr =  {5,3,1,2,6};Stream.of(arr).sorted().forEach(arr3-> System.out.println(arr3));}
}

如果比较的是对象,对象要实现comparable接口,重写compareto方法。

limit

可以设置stream的最大长度,超出的部分会被抛弃

package com;import java.util.stream.Stream;public class StreamTest8 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};Stream.of(arr).limit(2).forEach(arr3-> System.out.println(arr3));}
}
skip

跳过stream流中的前n个元素,返回剩下的元素。

package com;import java.util.stream.Stream;public class StreamTest9 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};Stream.of(arr).skip(2).forEach(arr3-> System.out.println(arr3));}
}
flatmap

map只能把一个对象转换成另一个对象来作为流中的元素,而flatmap可以把一个对象转换成多个对象作为流中的元素
在上面那个author,book的例子中

        List<Author> authors  = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).forEach(book -> System.out.println(book));

如果是使用map,那只能转换成book的集合
上面 author.getBooks()返回的是一个list对象,而这个匿名类是需要返回stream类型的,所以还需要把list转换成stream流。

而这个会把集合中的每个元素都变成stream流中的元素。
在这里插入图片描述

在上面那个author,book的例子中,输出书籍的分类

authors.stream().flatMap(author -> author.getBooks().stream()).flatMap(book->Arrays.stream(book.getCategory().split(","))).forEach(category-> System.out.println(category));}

终结操作

使用stream流必须要有终结操作,不然其他的操作都不会执行。使用了流方法之后,stream流就关闭了,不能继续使用链状方式继续调用方法了。

foreach

对stream流中的元素进行遍历操作,通过传入的参数去指定对遍历到的元素进行具体的操作。上面的例子都用到了。

count

可以用来获取stream流中的元素个数。

package com;import java.util.stream.Stream;public class StreamTest10 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};long count = Stream.of(arr).count();System.out.println(count);}
}
max

获得stream流中的最大值

package com;import java.util.Optional;
import java.util.stream.Stream;public class StreamTest11 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};Optional<Integer> max = Stream.of(arr).max((a, b) -> a - b);System.out.println(max.get());}
}
min

获得stream流中的最小值

package com;import java.util.Optional;
import java.util.stream.Stream;public class StreamTest12 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};Optional<Integer> min = Stream.of(arr).min((a, b) -> a - b);System.out.println(min.get());}
}
collect

把当前stream流转换成一个集合。
在上面那个author,book的例子中:
获取一个存放所有作者名字的list集合

        List<Author> authors  = getAuthors();List<String> nameList = authors.stream().map(author -> author.getName()).collect(Collectors.toList());System.out.println(nameList);

获取一个所有书名的set集合

        List<Author> authors  = getAuthors();Set<Book> bookSet = authors.stream().flatMap(author -> author.getBooks().stream()).collect(Collectors.toSet());System.out.println(bookSet);

获取一个map集合,map的key是作者的名字,value是List< book>

        List<Author> authors  = getAuthors();Map<String, List<Book>> collect = authors.stream().distinct().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));System.out.println(collect);

查找和匹配方法

anyMatch

判断stream流中是否有任意符合匹配条件的元素,返回boolean。

package com;import java.util.Optional;
import java.util.stream.Stream;public class StreamTest13 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};boolean b = Stream.of(arr).anyMatch(a -> a == 1);System.out.println(b);}
}
allMatch

判断stream流中所有的元素都符合匹配条件,返回boolean。

public class StreamTest14 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};boolean b = Stream.of(arr).allMatch(a -> a > 0);System.out.println(b);}
}
noneMatch

判断stream流中所有的元素都不符合匹配条件,返回boolean。

package com;import java.util.stream.Stream;public class StreamTest15 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};boolean b = Stream.of(arr).noneMatch(a -> a < 0);System.out.println(b);}
}
findany

获取stream流中的任意一个元素。

package com;import java.util.Optional;
import java.util.stream.Stream;public class StreamTest16 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};Optional<Integer> a = Stream.of(arr).findAny();System.out.println(a.get());}
}

奇怪的是一直返回1.

findfirst

获取流中的第一个元素。

package com;import java.util.Optional;
import java.util.stream.Stream;public class StreamTest17 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};Optional<Integer> a = Stream.of(arr).findFirst();System.out.println(a.get());}
}

reduce归并

对stream流中的数据按照指定的计算方式计算出一个结果。会传入一个初始值,这个初始值会和stream流中的元素(循环遍历每一个)进行计算,得到的结果赋值给这个初始值变量,继续下一个元素(下一轮的循环),最后得到一个结果。
它的底层代码是:
在这里插入图片描述

在上面那个author,book的例子中:
计算作者的年龄的总和

        List<Author> authors  = getAuthors();Integer sun = authors.stream().map(author -> author.getAge()).reduce(0, (result, element) -> result + element);System.out.println(sun);

解析:
reduce(0, (result, element) -> result + element)这行代码中的0就是初始值。
有点类似于

package com;import java.util.Optional;
import java.util.stream.Stream;public class StreamTest18 {public static void main(String[] args) {Integer[] arr =  {1,2,3,4,5};int sum = 0;for(Integer i:arr){sum = sum + i;}System.out.println(sum);}
}
使用reduce求最大值
package com;import java.util.ArrayList;
import java.util.List;public class StreamTest19 {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(2);list.add(3);list.add(1);Integer min = list.stream().reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);System.out.println(min);}
}
传入一个参数的reduce方法

底层的实现是:
在这里插入图片描述
相当于是把stream流中的第一个元素赋值给了result。

stream流的注意事项

  • 如果没有终结操作,流的操作是不会开始执行的
  • 流式一次性的,使用了终结操作以后,是不能再使用了
  • 对stream流里面的元素做了很多的处理操作,但这些都不会影响到原来的集合中的元素的。

相关文章:

  • Vue学习---vue 防抖处理函数,是处理什么场景
  • leetcode刷题日记-岛屿数量
  • OpenTeleVision复现及机器人迁移
  • 实验八: 彩色图像处理
  • Winform上位机TCP客户端/服务端、串口通信
  • Elasticsearch:Golang ECS 日志记录 - zerolog
  • 【PyTorch】单目标检测项目部署
  • js+css侧边导航菜单 可收缩
  • 【数据结构】排序算法——Lesson2
  • 树莓派自制智能语音助手之语音唤醒
  • 《人生苦短,我用python·十一》python网络爬虫的简单使用
  • 基于Hutool实现自定义模板引擎,实现json个性化模板引擎转换
  • 机器学习 | 回归算法原理——最小二乘法
  • SQL labs-SQL注入(三)
  • 离散型以及连续型随机变量
  • JS 中的深拷贝与浅拷贝
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • 03Go 类型总结
  • android 一些 utils
  • ECMAScript入门(七)--Module语法
  • hadoop集群管理系统搭建规划说明
  • MaxCompute访问TableStore(OTS) 数据
  • Mocha测试初探
  • Redis中的lru算法实现
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 聊聊redis的数据结构的应用
  • 线上 python http server profile 实践
  • 一起参Ember.js讨论、问答社区。
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • Hibernate主键生成策略及选择
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • 正则表达式-基础知识Review
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #java学习笔记(面向对象)----(未完结)
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (NSDate) 时间 (time )比较
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (安卓)跳转应用市场APP详情页的方式
  • (纯JS)图片裁剪
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (二)c52学习之旅-简单了解单片机
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (四十一)大数据实战——spark的yarn模式生产环境部署