Java 帝国之函数式编程(下)

上一篇文章《Java帝国之函数式编程(上)》说到Java帝国为了迎合函数式编程的狂热分子,决定为Java语言加上Labmda表达式。


同时为了展示“声明式”编程的魅力, 小码哥决定加上一个新的概念: Stream。


等到一切准备停当,  我们召开了一场开发者大会, 决定隆重推出Java 函数式编程。 

1. Stream

小码哥首先展示了Labmda表达式 和 类型推断, 大家还比较满意, 台下有人说:


“嗯, 和微软的C#长的挺像的, 人家用 =>   ,我们用 ->   ”


等到小码哥开始介绍Stream的时候, 下面就有人发难了:


“我们不是已经有IO流了吗, 字节流,字符流, 怎么又搞个流出来?”


小码哥赶紧解释: “这个Stream和IO流是不一样的, 这是个新的概念, 主要是为了实现LISP中常见的延迟计算(或者惰性求值)的功能”


看到下面的人开始交头接耳, 小码哥说: “大家别着急,先看看这一段代码:”


public class EvenNumber implements 

                    Supplier<Long>{

    long num = 0;

    @Override

    public Long get() {

        num += 2;

        return num ;

    }    

}


如果持续调用这个类的get()方法, 就可以得到所有的偶数, 现在我们就可以用它产生一个流:


Stream<Long> numbers = Stream.generate(

new EvenNumber());


这个Stream 其实就代表了一个无穷无尽的偶数序列, 只是它还没有计算出来而已( 惰性的/延迟的)

如果试图打印每个元素,那就开始计算了,  你就发现它会一直运行下去


numbers.forEach(x->System.out.println(x));


当然,无限的序列是无意义的, 各位在编程中肯定会限定长度的: 


numbers.limit(5).forEach(x->System.out.println(x));

输出: 2 4 6 8 10

2. 延迟计算

现在台下的人安静了,  小码哥有了信心, 开始介绍对Java 集合框架的改进:


“为了方便大家使用函数式风格,我们对集合框架中的类库做了极大的增强, 每个集合都可以变成一个stream , 然后就可以使用那些著名的map , reduce , filter 等函数了”


Arrays.asList("Hello","Java8","Java7").stream()

            .map(s -> s.toUpperCase())         


map 是个高阶函数, 它接受了一个Labmda表达式(匿名函数)作为参数, 把Stream中的元素做了变换: 字符串变成了大写 , 然后返回了一个新的Stream 


这也是延迟计算, 即使你加了一个打印语句, 也不会有任何任何输出:


 Arrays.asList("Hello","Java8","Java7").stream()

    .map(s -> {

            System.out.println(s);

            return s.toUpperCase();

            });


由于map 返回了一个新的Stream, 可以在新的Stream上继续操作, 例如filter :  把以J开头的字符串找出来,  filter 的结果仍然是个Stream.


Arrays.asList("Hello","Java8","Java7").stream()

     .map(s ->s.toUpperCase())

     .filter(s -> s.startsWith("J"));


最后你就可以用forEach 输出了,和惰性求值相反, forEach 是个立即求值的函数:


Arrays.asList("Hello","Java8","Java7").stream()

    .map(s ->s.toUpperCase())

    .filter(s -> s.startsWith("J"))

    .forEach(s -> System.out.println(s));


如你所料,  这里的输出是:

JAVA 8

JAVA 7


台下有人举手问到: “既然是延迟计算, 那列表中的元素在流中到底是怎么处理的?”


小码哥回答:“这是个好问题, 我们加点打印语句看看:”


Arrays.asList("Hello","Java8","Java7").stream()

        .map(s -> {

            System.out.println("map: "+ s);

            return s.toUpperCase();})

        .filter(s -> {

            System.out.println("filter:"+ s);

            return s.startsWith("J");})

        .forEach(s -> System.out.println(s));


系统的输出是这样的:

map: Hello

filter:HELLO

map: Java8

filter:JAVA8

JAVA8

map: Java7

filter:JAVA7

JAVA7


由此可以看出, 系统先取到初始Stream 中的第一个元素“Hello” , 做map操作,变成 "HELLO",  然后传递给 filter , filter 做了判断, 发现不是以"J" 开头的字符串, 立刻停止, 不会走到forEach那里。


接下来取第二个元素"Java8 ", 再经过map, filter, 这时候发现符合规则, 就走到了forEach 那里, 打印出来了。 


对第三个元素“Java 7” 也是类似处理


还有人问道: “s ->s.toUpperCase()  是不是和java.util.function.Function  这个接口相匹配?


小码哥说: “是的, 这是JDK内置的一个接口, 还有那个s->s.startsWith("J")  和 java.util.function.Predicate  匹配,  这是为了方便大家编程, 不用自己写函数接口了”


“除了map, filter, 还有哪些可以用的内置函数?”


小码哥说: “我们内置了很多, 像reduce , max ,min , collect, flatMap, 大家可以看看我们会议分发的手册, 使用这些函数, 我们就不用考虑集合处理的细节了, 基本上能做到声明式编程了。”


我看出大家有点小失望, 毕竟和纯正的函数式编程相差还比较远, 只能说是给面向对象的Java 增加了一点函数式的特性。 

3. 函数式编程的好处

这时候台下有个热爱Ruby 的家伙叫了起来: “啊 !  我知道怎么利用Java函数式编程写出Ruby 风格的代码了,举个例子”


public class Connection {

    public void open(){

        System.out.println("Open connection");

    }

    public void close(){

        System.out.println("Close connection");

    }

    public void read(){

        System.out.println("Read from connection");

    }

}


正常的使用是这样的, 调用方很麻烦, 得用try finally 确保连接关闭。


Connection conn = new Connection();

conn.open();

try{

    conn.read();

 }finally{

     // 一定得确保连接在finally中关闭

    conn.close();    

}


有了函数式编程, 我们可以在Connection 添加这么一个函数:

public class Connection {

    ......

 注意这个方法, 它已经把打开连接,关闭连接搞定了    

public static void open(

       Consumer<Connection> consumer){

        Connection conn = new Connection();

        conn.open();

        try{

            consumer.accept(conn);

        }finally{

            conn.close();

        }

    }

}


然后调用方就简单了: 

Connection.open(conn -> conn.read());


用这种方式, 调用方根本不用处理连接的打开和关闭问题了 !  只需要关注自己想要调用的逻辑

实在是太爽了!

 

这和Ruby 风格非常像 :

Connection.open do |conn|

    conn.read

end


我和小码哥都大喜过望: 没有想到还有这么一个同盟军 ! 


另外一个家伙说:“这的确是个好例子, 其实大家想想在java 世界大行其道的设计模式, 很多时候设计模式就是想把一个行为封装起来, 到处传递而已, 只是当时我们没有函数式编程的概念, 只好用个类来封装一个行为,显得很笨拙, 最典型的就是策略模式。”


小码哥回应说: “对的, 大家可以充分的发掘一下函数式编程的威力, 不但可以简化集合框架的操作, 还能简化代码,  简化设计模式, 甚至也能向Ruby那样,开发出领域特定语言(DSL)出来 。 ”

4. 并行

我看发布会临近尾声, 小码哥竟然还没有介绍并行化, 赶紧提醒他: 小码,快讲讲数据并行化啊。

 

“对了, Java 函数式编程还给大家提供了另外一件福利:并行化“ 小码哥终于要补上这一项了


“把代码变成并行化代码异常简单, 只需要把stream()操作改成 parallelStream() 就可以了, 例如下面这个计算素数的程序”


List<Integer> numbers= .....

List<Integer> prims = numbers.parallelStream()

    .filter(i -> Util.isPrim(i) )

    .collect(Collectors.toList())


“再比如对数组的并行排序:Arrays.parallelSort(), 只需要做一点点改动, 剩下的工作就交由Java 来完成了, 我们会把数据自动进行分块, 分配到各个CPU核心上去运行, 最后把结果收集回来, 一个简单的变化就能极大的提升性能。”


我听到台下响起了欢呼声!


但是小码哥接着就泼了一盆冷水: ”使用并行stream的时候要注意,它不一定100%能提高性能,因为这依赖很多因素 ,例如输入的数据是否容易分解成块, 是不是CPU密集型的任务, 有没有IO等待操作等等...... ”


我就知道技术人员太老实 ,不会忽悠, 眼瞅着热烈的气氛要冷却下来,  我赶紧上台, 抢过话筒说: “这些细节大家下来再和小码哥聊吧, 我们今天的发布会就到这里, 再见。” 


Java 的函数式编程就这么发布了, 帝国程序员的工具箱里又多了一件工具,  虽然不是纯正的函数式编程, 但我们确实可以用它来写出更简洁的代码, 希望大家能够喜欢它。 


声明:原创文章,未经授权,禁止转载


你看到的只是冰山一角, 更多精彩文章,尽在“码农翻身” 微信公共号, 回复消息“m” 或者“目录” 查看更多文章。

我是一个线程

我是一个Java class

Javascript: 一个屌丝的逆袭

Java : 一个帝国的诞生

Basic : 一个老兵的自述

小王的架构师之路

程序员在工作中必备的能力

码农需要知道的潜规则

TCP/IP 之 大明王朝的邮差

CPU 阿甘

IE为什么把Chrome和火狐打伤了

Node.js :我只需要一个店小二

假如我是计算机系老师

假如时光倒流,我会这么学Java

学会编程,而不是学会Java

15年编程生涯,资深架构师总结的7条经验


0?wx_fmt=jpeg

公共号:码农翻身

“码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。

内容概要:本文提出了一种基于非合作博弈理论的居民负荷分层调度模型,并结合双层鲸鱼优化算法(Two-level Whale Optimization Algorithm)进行高效求解,模型与算法均通过Matlab代码实现。研究针对电力系统中居民侧用电负荷的复杂调度问题,引入非合作博弈机制刻画各用户之间的利益竞争关系,实现负荷的分层优化分配;同时设计双层优化架构,上层优化资源配置,下层模拟用户自主决策行为,提升了模型的实用性与合理性。通过智能优化算法求解多层级、非凸非线性的博弈模型,有效提高了调度方案的收敛性与全局寻优能力,适用于现代智能电网中的需求侧管理与能源优化场景。; 适合人群:具备电力系统基础理论知识和Matlab编程能力,从事智能电网、能源优化调度、需求侧管理、博弈论应用等方向的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①应用于居民区电力负荷的分层优化调度系统设计与仿真分析;②为非合作博弈在多主体能源系统建模中的应用提供方法论支持;③利用双层鲸鱼算法解决具有嵌套结构的复杂双层优化问题,提升求解效率与调度方案的可行性。; 阅读建议:建议读者结合提供的Matlab代码深入理解模型构建逻辑与算法实现流程,重点关注博弈模型的效用函数设计、纳什均衡求解思路以及双层优化结构的迭代机制,宜配合实际用电数据开展复现实验以验证模型有效性与鲁棒性。
内容概要:本文围绕基于自适应神经模糊推理系统(ANFIS)智能控制器的可再生能源微电网功率管理系统展开研究,结合Simulink仿真实现,深入探讨了微电网中功率的智能调控与经济机组组合调度问题。通过引入ANFIS控制器,有效应对风能、光伏等可再生能源出力的波动性与不确定性,提升系统运行的稳定性与电能质量。研究内容涵盖微电网多源协调控制策略、功率平衡管理、优化调度模型构建及仿真验证,实现了对分布式电源、储能系统和负荷的协同优化,兼顾经济性与可靠性目标,并通过仿真平台验证了所提方法的有效性与优越性。; 适合人群:具备电力系统、自动化或新能源相关专业背景,熟悉Matlab/Simulink仿真环境,从事微电网能量管理、智能控制、能源优化等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于高比例可再生能源接入场景下的微电网能量管理系统研发与教学实践;②为实现微电网功率稳定控制与经济高效运行提供先进的智能控制解决方案;③支撑高水平学术论文复现、科研课题攻关及实际工程项目的仿真验证与方案优化。; 阅读建议:建议结合提供的Simulink模型与相关代码进行动手实践,重点关注ANFIS控制器的设计流程、规则库构建与参数调优方法,并通过与传统PID或MPC控制策略的对比实验,深入理解其在动态响应与鲁棒性方面的优势。同时可进一步拓展文中提出的优化调度逻辑,应用于多目标、多约束的复杂实际应用场景中。
内容概要:本文档聚焦于“直流电机双闭环控制Matlab仿真”,系统阐述了基于Matlab/Simulink平台实现直流电机双闭环控制系统(主要包括速度环与电流环)的设计与仿真全过程。通过构建直流电机的数学模型,结合PI控制器进行调控,实现对电机转速和电枢电流的高精度动态控制,验证控制策略的稳定性与响应性能。文档详细介绍了仿真模型的搭建流程、关键参数的整定方法、系统动态波形的分析手段以及仿真结果的有效性验证,体现了经典自动控制理论在实际电机系统中的工程应用,是电机控制与电力电子技术相结合的典型研究案例。; 适合人群:具备自动控制原理、电机与拖动基础、电力电子技术和Matlab/Simulink仿真能力的电气工程、自动化、机电一体化等专业的本科生、研究生及从事电机驱动系统研发的工程技术人员。; 使用场景及目标:①作为高校课程设计或实验教学材料,帮助学生深入理解双闭环调速系统的工作机理与工程实现;②服务于科研项目,为新型电机控制算法(如滑模、模糊PID等)的开发与性能对比提供基础仿真验证平台;③作为工业界产品前期设计的仿真工具,用于评估不同控制策略在动态响应、抗干扰能力和稳态精度方面的可行性。; 阅读建议:建议读者在学习过程中紧密结合自动控制理论知识,亲手在Simulink环境中搭建完整的双闭环仿真模型,通过反复调整PI控制器的比例与积分参数,观察并分析转速、电流的阶跃响应曲线,从而深刻理解反馈控制的本质、系统稳定性条件以及参数整定对动态性能的影响,进而掌握电机控制系统的设计精髓。
内容概要:本文研究了基于Benders分解与输电网运营商(TSO)和配电网运营商(DSO)协调机制的不确定环境下输配电网双层优化模型,旨在提升高比例可再生能源接入背景下电网系统的协调性与鲁棒性。模型上层以系统整体经济性为目标进行优化调度,下层采用Benders分解实现TSO与DSO之间的信息交互与协同决策,通过引入割平面迭代机制保障求解的收敛性与全局最优性。研究充分考虑新能源出力与负荷需求的不确定性,构建了具有强适应性的双层优化框架,并基于Matlab完成了模型的编程实现与仿真验证,有效解决了多主体、多层级、多不确定性因素耦合下的电力系统优化调度难题。; 适合人群:具备电力系统分析、运筹学与优化理论基础,熟悉Matlab编程环境,从事智能电网、能源互联网、分布式能源集成、电力市场等方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究高渗透率可再生能源条件下输配电网协同优化调度策略;②掌握Benders分解在电力系统双层优化建模中的应用方法与实现技巧;③构建TSO-DSO多主体协调机制,实现跨层级电网资源的高效互动与决策解耦;④提升对不确定性建模、分解算法设计及大规模优化问题求解能力。; 阅读建议:建议读者结合Matlab代码逐模块剖析模型构建流程,重点理解Benders割的生成逻辑、主从问题的信息传递机制及收敛判据设定,推荐在标准IEEE测试系统上复现实验以深入掌握模型特性与算法性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值