首页 > 编程语言 >JAVA函数式编程

JAVA函数式编程

时间:2024-07-02 23:56:32浏览次数:20  
标签:JAVA 函数 Stream 收集器 编程 接口 表达式

函数式编程概念,JAVA八新特性Lambda表达式和流(Stream)的使用。

一、基本概念

命令式编程:是一种描述计算机所需作出的行为的编程典范。主要思想是关注计算机执行的步骤,计算机则会严格遵循指令。

  传统的硬件运行的机器码指令就是以命令式分格编写的。也就是对于需要实现的功能,要编写指令明确指出计算机应该如何实现。从冯诺依曼体系结构来看,就是CPU每次对这些指令取指、译码、执行,然后把结果写回内存。因此命令式编程就是对这些操作的抽象。

声明式编程:与命令式编程相对立,它描述目标的性质,让计算机明白目标,而非流程。即声明式编程不用告诉计算机问题领域,从而避免随之而来的副作用。而命令式编程则需要用算法来明确的指出每一步该怎么做。

  声明式编程通常被看做是形式逻辑的理论,把计算看做推导。因此其通常由若干规范的声明组成,是人脑思维方式的抽象,利用数理逻辑或既定规范对已知条件进行推理或运算。典型的声明式编程语言如数据库查询语言SQL,只需要指明需要的数据和条件,底层实现由数据库完成。

函数式编程:是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。

  函数式编程是声明式编程的一部分,它们思想是一致的,即只关注做什么而不是怎么做。但函数式编程利用函数可作为参数的特点,使得函数可以出现在任何地方。同时其具有不可变性,即函数不存在副作用,如果要修改则需克隆新的备份数据。(如j = i ++,其中i ++ 获取到i的值,但是副作用是使得i的值加1)

二、Lambda表达式

Lambda表达式:相当于一个没有名字的函数,基本格式就是(参数)->(代码块)。->将参数和表达式主体分开,其相对于匿名内部类则无需显式指定参数类型。是一种更为紧凑的、传递行为的方式。

  Lambda表达式除了基本形式外,还有不同的变体。表达式的参数类型都是由编译器推断得到。而Lambda表达式的目标类型则指表达式所在的上下文环境,将表达式赋给一个局部变量或方法参数,局部变量或方法参数就是其目标类型。

  使用匿名内部类时,要引用它所在方法里的变量,就需要将变量声明为final。Lambda表达式内部使用外部变量同样需要是final或者是既成事实上的final类型。因为Lambda表达式引用的是值而非变量,因此声明为final就可以防止误解。

  Lambda表达式本身的类型其实是一个接口,称其为函数接口。这种接口的特点就是只有一个抽象方法被用来表示行为,方法命名并不重要。只要方法签名和Lambda表达式类型匹配即可。函数接口中的单一方法参数可以自由指定,同时也可以使用泛型,通过类型推断得出具体类型。

三、Java中重要的函数接口

断言型接口Predicate<T>:Predicate接口返回一个Booolean的参数,该函数只有一个输入参数。接口中包含多种默认方法,用于处理复杂的逻辑动词。

功能型接口Function<T,R>:Function接口接收一个参数,并返回单一的结果。默认方法可以将多个函数串在一起。

功能型接口BinaryOperator<T>:和Function不同的是该接口接收两个参数,返回一个结果。

供给型接口Supplier<T>:Supplier接口产生一个给定类型的结果。与Function不同的是,Supplier没有输入参数。

消费型接口Consumer<T>:Consumer代表了在一个输入参数上需要进行的操作,函数返回值为void。

四、常用流操作

Java引入Stream API,对于传统集合的操作由外部迭代转为内部迭代,省去了多余循环模板。可以说Stream就是函数式编程方式在集合类上进行复杂操作的工具。

collect(toList())
  该方法由Stream里的值生成一个列表,是一个及早求值的操作。其中toList()也可以改成toSet(),即将Stream里的值生成一个集合。

map
  map操作接收一个Function接口实例,其作用就是一种类型构成的Stream转换为另一个中类型构成的Stream。完成转换工作的就是Fuction接口实例。

filter
  filter操作接收一个Predicate接口实例,其作用就是起到过滤的作用。对于由许多值构成的Stream,对于其中的每个值经过Predicate接口函数都会返回true或者false值,而经过filter操作的Stream就过滤了所有结果为false的值,最终所有经Predicate接口计算为true的值构成新的Stream返回。

flatMap
  flatMap和map操作很像,也是接收一个Function接口实例。不同之处在于flatMap将原Stream的每个值转换为一个Stream,且其还负责将这些转换的Stream连接成一个Stream。

max和min
  max和min操作就是求最大值和最小值,操作接收的是Comparator接口实例,同时返回一个Optional实例。Optional对象的作用就是表示一个可能存在也可能不存在的值,如Stream为空那么值就不存在,调用get的方法就可以获取值且内部还对空值做了检测。

reduce
  该操作可以实现从一组值中生成一个值,可以发现count、max、min操作都是reduce操作。reduce操作接收一个初值和BinaryOperator实例,每次将计算结果累加到初值,得到一个最终结果。

五、高级集合类和收集器

方法引用:方法引用是对Lambda进一步简写,可以重用已有方法。且和常规的方法调用不同,使用方法引用时可以省去括号。(如创建对象可以表示成String::new)

  之前使用collect(toList())将Stream转换为列表,其中toList()就是一个收集器,类似的还有toSet()、toCollection()。这些收集器将Stream转换为其他集合。类似的还有maxBy、minBy可以将Stream转换成值的收集器,将比较器传入这些收集器,在将收集器传给collect就可以实现转换。收集器averagingInt则可以求出平均值。收集器Collectors.joining是针对字符串流,将流中所有字符串指定分隔符、前缀、后缀进行拼接成一个字符串。

  还有另外一些收集器可以实现将数据分块,如partitioningBy收集器,接收一个Predicate接口实例,并将该收集器传给collect就可以将流的数据分成两部分。结果为true的一组和为false的一组并以Map<Boolean, List<T>>的形式返回。

  处理数据分块收集器,还有数据分组收集器即groupingBy,相比于partitioningBy其支持任意值对数据进行分组。因此groupingBy接收的是Function接口实例,分组结果以Map<T, List<R>>的形式展现。

六、并行化流操作

并行和并发:并发是指两个任务共享时间段,并行则是两个任务在同一个时间发生。并发通常发生在一个CPU给两个任务分配时间片交叉执行,而并行多发生在多核CPU上。

  在Stream的设计中,调用其parallel方法就能让其拥有并行操作的能力,而对于集合调用parallelStream也可以获得一个拥有并行能力的流。相比于串行流、并行流在reduce操作上有所限制。且并行化流性能并不总优于串行流,通常并行化流在简单操作处理大量数据上发挥的性能更好。

标签:JAVA,函数,Stream,收集器,编程,接口,表达式
From: https://www.cnblogs.com/idempotent/p/12168877.html

相关文章

  • 【hash】hash算法、hash函数、哈希表、布隆过滤器、一致性哈希
    哈希函数的基本性质函数定义域是无穷的,值域相对有限(但也很大,比如2的64次方)输入同样样本一定得到同样的输出输入不同样本可能得到相同输出,此时叫哈希碰撞输入大量不同的样本,得到大量输出值,会几乎均匀的分布在整个输出域上布隆过滤器通过几个不同哈希函数计算哈希值,对位......
  • 掌握这些快捷键,提升你的编程效率!
    文章目录执行代码行操作移动光标查看源码编辑常用操作类操作方法操作文件操作快捷键组合结语......
  • JAVA并发工具类
    JAVA中并发工具类CountDownLatch、CyclicBarrier和Semaphore的概念和使用。一、CountDownLatch(计数器)  CountDownLatch的应用场景是某个线程任务需要等待其他的线程全部执行完毕才能执行,这时候就可以使用CountDownLatch类。其内部使用计数器实现,计数器的初始值为线程的数......
  • JAVA并发知识
    JAVA常见的并发知识点,概念和使用方法。一、Synchronized和Lock的区别Synchronized:Synchronized是Java提供的关键字,可以在需要同步的对象中加入此控制。其可以用来修辞方法,也可以加在特定代码块中,而修辞特定代码块时括号中表示需要锁的对象。JVM底层实现:  Synchronized......
  • JAVA文件IO流
    基本的目录、文件操作,常用的IO输入输出流类介绍和使用。一、目录及文件操作Java中File类(文件类)以抽象的方式代表文件名和目录路径名,File对象则代表了磁盘中实际存在的文件和目录。  File类不仅仅提供灵活的构造方法,同时还可以用于文件和目录的创建、文件的查找和文件的......
  • 请编写函数fun,该函数的功能是:统一一含字符串中单词的个数,作为函数值返回。一行字符串
    /请编写函数fun,该函数的功能是:统一一含字符串中单词的个数,作为函数值返回。一行字符串在主函数中输入,规定所有单词由小写字母组成,单词之间由若干个空格格开,一行的开始没有空格。/#include<stdio.h>#include<time.h>#include<stdlib.h>#defineN200intfun(char*buff)......
  • Python 引用不确定的函数
    在Python中,引用不确定的函数通常意味着我们可能在运行时才知道要调用哪个函数,或者我们可能想根据某些条件动态地选择不同的函数来执行。这种灵活性在处理多种不同逻辑或根据不同输入参数执行不同操作的场景中非常有用。以下是如何实现这一点的详细介绍和具体代码示例。1.Python......
  • 【C++ | 继承】|概念、方式、特性、作用域、6类默认函数
    继承1.继承的概念与定义2.继承的方式2.1继承基本特性2.2继承的作用域2.2.1隐藏赋值兼容派生类的创建和销毁构造函数拷贝构造赋值重载1.继承的概念与定义继承是面向对象编程中的一个重要概念。它的由来可以追溯到软件开发中的模块化设计和代码复用的需求。在软件......
  • 学懂C#编程:常用高级技术——学会C#的高级特性 LINQ
    LINQ(LanguageIntegratedQuery)是C#中的一项强大特性,它允许开发者以一种统一的方式查询和操作各种数据源,如集合、数据库、XML等。LINQ将查询功能直接集成到C#语言中,使得数据查询和操作变得更加直观和高效。LINQ的基本概念LINQ的核心思想是将数据查询表达为一种类似于SQL的查......
  • 请编写函数fun,该函数的功能使:统计各年龄段的人数。N个年龄通过调用随机函数获得, 并放
    /请编写函数fun,该函数的功能使:统计各年龄段的人数。N个年龄通过调用随机函数获得,并放在主函数的age数组中;要求函数把0至9岁年龄段的人数放在d[0]中,把10至19岁年龄段的人数放在d[1]中,把20至29岁的人数放在d[2]中,其余以此类推,把100岁(含100以上年龄的人数都放在d[10]中。结果在主......