实习前只是粗略的看了下Java8的一些基本语法,但是没有系统的学习过.在使用一段时间后决定系统的对其进行一次分析,加深对Java8函数式编程的理解,提高自己的编码技巧.另外kotlin崛起,感兴趣的朋友尝试下混编也未尝不可.


函数式接口

函数式接口,对于Java来说就是接口内只有一个公开方法的接口,因为使用lanbda表达式,例如() -> user.getName()对应的调用则可能是func.get(),编译器会根据接口推断所属于的方法,如果有两个则无法推断.Java8提供了很多函数式接口,一般都使用注解@FunctionalInterface声明,有必要了解如下一些函数式接口.

函数式接口 参数类型 返回类型 描述
Supplier T 接收一个T类型的值
Consumer T 处理一个T类型的值
BiConsumer T,U 处理T类型和U类型的值
Predicate T boolean 处理T类型的值,并返回true或者false.
ToIntFunction T int 处理T类型的值,并返回int值
ToLongFunction T long 处理T类型的值,并返回long值
ToDoubleFunction T double 处理T类型的值,并返回double值
Function T R 处理T类型的值,并返回R类型值
BiFunction T,U R 处理T类型和U类型的值,并返回R类型值
BiFunction T,U R 处理T类型和U类型的值,并返回R类型值
UnaryOperator T T 处理T类型值,并返回T类型值,
BinaryOperator T,T T 处理T类型值,并返回T类型值

以上的函数每一个代表的都是一种基本的操作,操作之间可以自由组合,所以才有了stream这些灵活的操作.

Stream操作

Stream的操作是建立在函数式接口的组合上的,最好的学习方法是看Stream接口来学习.下面举一些例子来分析,假设有这样的一些初始数据.

List<String> testData = new ArrayList<String>();testData.add("张三");testData.add("李四");testData.add("王二");testData.add("麻子");复制代码

filter

    Stream<T> filter(Predicate<? super T> predicate);复制代码

filter接收predicate函数,predicate是接收T值,返回boolean值,那么对应的引用就可以写成如下形式,意思是取集合中以'张'开头的名字.

testData.stream().filter(x -> x.startsWith("张"))复制代码

map

    <R> Stream<R> map(Function<? super T, ? extends R> mapper);复制代码

map操作接收的是Function接口,对于Function接收T值返回R值,那map的作用就很明显是转换用的,比如下面代码,转换名称为对应的名称长度,也就是从输入String数据返回int数据.

testData.stream().map(x -> x.length())复制代码

flatMap

    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);复制代码

flatMap和map都是使用Function接口,不同的是返回值flatMap限定为Stream类型.所以flatMap可以作为合并流使用,如以下代码,提取出所有的字符.

testData.stream().flatMap(x -> Stream.of(x.split(""))).collect(Collectors.toList());//输出  [张, 三, 李, 四, 王, 二, 麻, 子]复制代码

peek

    Stream<T> peek(Consumer<? super T> action);复制代码

peek参数为Consumer,Consumer接收T值,无返回,那么该方法就可以作为调试不影响stream中内容的一些操作,不过由于对象都是地址引用,你再此做一些对象内容操作也是可以的.
reduce

<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);复制代码

Reduce比较复杂的一个接口,属于归纳性操作,看参数,第一个是U泛型,也就是输入类型的参数,最为初始值,第二个BiFunction,接收T,U参数,返回U类型参数,BinaryOperator接收U,U类型,并返回U类型.

    StringBuilder identity = new StringBuilder();StringBuilder reduce = testData.stream().flatMap(x -> Stream.of(x.split(""))).reduce(identity, (r, x) -> {r.append(x);return r;}, StringBuilder::append);System.out.println(identity == reduce);System.out.println(reduce.toString());//输出 true//  张三李四王二麻子复制代码

首先提供一个基本容器identity,然后两个参数r即是identity,x为每次输入参数,最后一个StringBuilder::append是并发下多个identity的合并策略.
再举个例子,既然reduce属于归纳性操作,那么也可以当成collect使用,如下:

 ArrayList<String> identity = new ArrayList<>();ArrayList<String> result = testData.stream().flatMap(x -> Stream.of(x.split(""))).reduce(identity, (r, x) -> {r.add(x);return r;},(r1,r2) -> {r1.addAll(r2);return r1;});System.out.println(identity == result);System.out.println(result);//输出 true//[张, 三, 李, 四, 王, 二, 麻, 子]复制代码

强大的collect

collect无疑是stream中最强大的操作,掌握了collect操作才能说掌握了stream.为了便于使用者,Java提供了Collectors类,该类提供了很多便捷的collect操作,如Collector<T, ?, List<T>> toList(),Collector<T, ?, Set<T>> toSet()等操作.这些操作最终都会调用如下构造函数构造出collector对象,因此掌握该本质是最佳的学习方式.

CollectorImpl(Supplier<A> supplier,BiConsumer<A, T> accumulator,BinaryOperator<A> combiner,Function<A,R> finisher,Set<Characteristics> characteristics) {this.supplier = supplier;this.accumulator = accumulator;this.combiner = combiner;this.finisher = finisher;this.characteristics = characteristics;}复制代码

Supplier类似reduce中的u,接收一个元数据,BiConsumer则是操作数据,BinaryOperator并发下聚合,finisher完成时的转换操作,Set应该按照定义是优化一些操作中的转换.如下面的toList()操作,其finish操作为castingIdentity().

   public static <T>Collector<T, ?, List<T>> toList() {return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,(left, right) -> { left.addAll(right); return left; },CH_ID);}复制代码

再看toMap的实现

    public static <T, K, U, M extends Map<K, U>>Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction,Supplier<M> mapSupplier) {BiConsumer<M, T> accumulator= (map, element) -> map.merge(keyMapper.apply(element),valueMapper.apply(element), mergeFunction);return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);}复制代码

Function作为转换函数提供了key和value的转换,BinaryOperator提供了重复key合并策略,mapSupplier则表示最终收集到的容器.那么使用就很简单了

HashMap<Character, String> map = testData.stream().collect(Collectors.toMap(x -> x.charAt(0), Function.identity(), (v1, v2) -> v2, HashMap::new));复制代码

其他还有很多方法,就不一一叙述,主要是了解这些接口,知道他所拥有的功能,以及组合的意义,即可很好的掌握Java中的函数式编程.

个人博客 mrdear.cn ,欢迎交流

Java8之Stream-函数式接口相关推荐

  1. Java8 Stream 函数式接口

    在这里插入图片描述 先贴上几个案例,水平高超的同学可以挑战一下: 从员工集合中筛选出salary大于8000的员工,并放置到新的集合里. 统计员工的最高薪资.平均薪资.薪资之和. 将员工按薪资从高到低 ...

  2. 未公开接口主要指以下哪几类_Java8的 Stream 函数式接口,你了解多少?

    点击蓝色"程序职场"关注我哟 加个"星标",天天和你一起进步 作者:litesky www.jianshu.com/p/2338cabc59e1 函数式接口是伴 ...

  3. Java8中Function函数式接口详解及使用

    文章目录 1.函数式接口 1.1允许定义默认方法 1.2允许定义静态方法 1.3允许定义java.lang.Object的public方法 1.4已有函数式接口 2.Function函数 2.1Fun ...

  4. java8新特性_乐字节-Java8新特性-函数式接口

    上一篇小乐带大家学过 Java8新特性-Lambda表达式,那什么时候可以使用Lambda?通常Lambda表达式是用在函数式接口上使用的.从Java8开始引入了函数式接口,其说明比较简单:函数式接口 ...

  5. java 8 函数式接口_必看:通俗易懂地告诉你什么是java8中的“函数式接口”

    花10分钟认真的看完一篇文章,或许会有意想不到的收获 java8发布已经好几年了,相信很多小伙伴都使用过java8,java8这版本带来了很多新特性,其中一个就是"函数式接口",今 ...

  6. Java8中的函数式接口Supplier、Consumer、BiConsumer详解

    目录 一.什么是函数式接口? 二.函数式接口应用实战 1. BiConsumer接口和Consumer接口 1) accept(T t,U u)方法 2) andThen(BiConsumer)方法 ...

  7. JAVA8特性之函数式接口-@FunctionalInterface注解

    函数式接口: 定义: 就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,总体有点像匿名类 @FunctionalInterface: 该注解可加可不加,它是函数式接口语法检查注解的,当然最 ...

  8. java8四大核心函数式接口(模拟实现,全网最通俗易懂)

    前言,如果不精通lamda表达式,请观看文章https://blog.csdn.net/wwwwwww31311/article/details/113116327 一.消费者接口 经典案例代码,怎么 ...

  9. java8 四大函数式接口 和 用于数据处理的 stream流 使用详解

    文章目录 Stream 使用示例 四大函数式接口 Function 功能型接口 Consumer 消费型接口 Supplier 提供型接口 Predicate 断言型接口 常用 api stream, ...

  10. Java8函数式接口与Lambda表达式

    摘要 何为函数式接口? 什么是lambda表达式,lambda表达式的本质: 函数式接口与lambda表达式的联系:lambda是实现函数式接口的一个快捷方式,可以作为函数式接口的一个实例: 常用Ja ...

最新文章

  1. python语言使用什么语句实现上下文管理协议_Python 技巧探究:上下文管理器和with语句...
  2. 金庸小说人物关系表年表
  3. 16.IDA-列出函数中存在的全部call
  4. cmd - 使用curl命令的注意点
  5. 郑州大学计算机学科导论,郑州大学计算机导论大一试题答案.doc
  6. vs已经引用mysql还是不能用_VS2013与MySql建立连接;您的项目引用了最新实体框架;但是,找不到数据链接所需的与版本兼容的实体框架数据库 EF6使用Mysql的技巧[转载]...
  7. java tomcat 读取配置文件端口_跟我学Java编程—应用读写项目配置文件的Properties类...
  8. 品牌直播启动的三个关键点
  9. 03 聚类算法 - K-means聚类
  10. oracle网络加载错误怎么解决,Oracle加载数据库错误解决的方法详细教程
  11. IDEA SpringBoot多模块项目搭建详细过程(转)
  12. kubectl配置tab补全
  13. android studio 模拟器 简书,Android Studio的模拟器genymotion
  14. Layui表单验证lay-verify属性
  15. 用虚拟机玩游戏的方法!! 开3D加速!
  16. CMYK配色表和RGB配色表
  17. 百度云文字识别demo
  18. 编写个人所得税计算程序
  19. 蓝桥杯2021年PYTHON 真题,跳房子
  20. 【LLM大模型】模型和指令微调方法

热门文章

  1. 西门子stl语言指令_STEP7项目的JL跳转指令你会用吗?
  2. java url 处理,URL处理-Java架构师必看
  3. visual studio 设计器不显示_面向国际市场的装置开发运维软件设计与实现
  4. php清空html_php怎么清除html代码
  5. 用力和应变片计算弹性模量_实验力学实验讲义(08.9).doc
  6. 数组元素的修改会影响到转换过来的结合_数组长度属性背后有什么魔力?
  7. centos7.2 安装mysql5.6_Centos7安装mysql5.6
  8. 深度学习tensorflow数据流图基础知识点
  9. python连接mongo数据库
  10. 一位大牛的JAVA学习资料