热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

高阶编程_具有高阶功能的编程风格的练习

高阶编程本周,该章名为“前进”。样式的约束不是直接调用函数,而是将其作为参数传递给下一个函数,稍后再调用。这是5在编程风格焦点series

高阶编程

本周,该章名为“前进”。 样式的约束不是直接调用函数,而是将其作为参数传递给下一个函数,稍后再调用。

这是5在编程风格焦点series.Other职位练习交包括:

  1. 以编程风格介绍练习
  2. 以编程风格进行练习,将内容堆叠起来
  3. 编程风格的练习,Kwisatz Haderach风格
  4. 编程风格的练习,递归
  5. 以高阶函数进行编程风格的练习 (本文)
  6. 以编程风格进行练习
  7. 以编程风格进行练习,回到面向对象的编程
  8. 编程风格的练习:地图也是对象
  9. 编程风格的练习:事件驱动的编程
  10. 编程风格的练习和事件总线
  11. 反思编程风格的练习
  12. 面向方面的编程风格的练习
  13. 编程风格的练习:FP&I / O
  14. 关系数据库风格的练习
  15. 编程风格的练习:电子表格
  16. 并发编程风格的练习
  17. 编程风格的练习:在线程之间共享数据
  18. 使用Hazelcast以编程风格进行练习
  19. MapReduce风格的练习
  20. 编程风格的练习总结

高阶函数

我不确定高阶函数的概念是否起源于函数式编程。 但是,这个概念本身很容易掌握:高阶函数可以用作另一个函数的函数参数或返回值。 从版本8开始,它在Java中可用,但是从其开始就在Scala和Kotlin中可用。

在Java中,它们主要与流结合使用:

Stream.of("A","B","C","D","E").map(newFunction<String,String>(){&#64;OverridepublicStringapply(Strings){returns.toLowerCase();}});}Stream.of("A","B","C","D","E").map(s->s.toLowerCase());Stream.of("A","B","C","D","E").map(String::toLowerCase);

前面的三行代码都完全一样&#xff0c;因为lambda映射到功能接口的匿名类。

在Kotlin中&#xff0c;这非常相似&#xff0c;但有2点&#xff1a;

  1. 没有Kotlin会写匿名类&#xff0c;正是因为自一开始就可以使用高阶函数
  2. 就像Groovy中一样&#xff0c;lambda的默认参数名称是it

Stream.of("A","B","C","D","E").map{it.toLowerCase()}Stream.of("A","B","C","D","E").map(String::toLowerCase)

调用函数

一旦将一个函数传递给另一个函数&#xff0c;下一个逻辑步骤就是调用它。 在Java中&#xff0c;需要知道高阶函数的类型。 例如&#xff0c;要执行一个Function &#xff0c;需要调用apply()并传递具有期望类型的参数。 要执行Predicate &#xff0c;该函数称为test()等。

Function<String,String>toLowerCase&#61;String::toLowerCase;
toLowerCase.apply("A");
Predicate<String>isLowerCase&#61;s->s.equals(s.toLowerCase());
isLowerCase.test("A");

Kotlin更加一致&#xff0c;因为在KCallable接口上定义了一个名为call()函数。

funisLowerCase(string:String)&#61;string&#61;&#61;string.toLowerCase()
valcallable:Boolean&#61;::isLowerCase.call("A")

但是&#xff0c; call()接受任意数量的Any?类型的参数Any? 。 调用者可以传递正确的数字和参数类型。 以下编译&#xff0c;但在运行时将失败&#xff1a;

valcallable:KCallable<String>&#61;::isLowerCase.call("A",2,Any())

为了从编译器中受益&#xff0c;可以使用KFunctionX类型&#xff0c;其中X是函数接受的参数数量。 该类型为invoke()函数提供了正确数量的参数及其类型。

valok:KFunction<String,Boolean>&#61;::isLowerCase.invoke("A") (1)
valko:KFunction<String,Boolean>&#61;::isLowerCase.invoke("A",2,Any()) (2)

  1. 编译
  2. 不编译

锦上添花&#xff0c; invoke()是一个运算符函数&#xff0c;该运算符什么都不是......因此以下语法也是有效的&#xff1a;

(::isLowerCase)("A")

应用理论

在本练习中&#xff0c;入口点函数将调用一个函数&#xff0c;该函数依次调用7个嵌套级别。 如果将KCallable更改为KFunction &#xff0c;则顶部函数具有以下非常“有趣”的签名&#xff1a;

funreadFile(filename:String,function:KFunction2<List<String>,KFunction2<List<String>,KFunction2<List<String>,KFunction2<List<String>,KFunction2<List<String>,KFunction2<List<Pair<String,Int>>,KFunction1<List<Pair<String,Int>>,Map<String,Int>>,Map<String,Int>>,Map<String,Int>>,Map<String,Int>>,Map<String,Int>>,Map<String,Int>>,Map<String,Int>>
):Map<String,Int>

尽管我相信静态类型化有很多好处&#xff0c;但是这当然不会使代码更易于阅读。 为了解决这个问题&#xff0c;Kotlin提供了类型别名 。 以下代码段使用它们来改善情况&#xff1a;

typealiasWordFrequency&#61;Pair<String,Int>
typealiasWordFrequencies&#61;List<WordFrequency>
typealiasLines&#61;List<String>
typealiasWords&#61;List<String>
typealiasMapFunction&#61;KFunction1<WordFrequencies,Map<String,Int>>
typealiasSortFunction&#61;KFunction2<WordFrequencies,MapFunction,Map<String,Int>>
typealiasFrequencyFunction&#61;KFunction2<Words,SortFunction,Map<String,Int>>
typealiasRemoveFunction&#61;KFunction2<Lines,FrequencyFunction,Map<String,Int>>
typealiasScanFunction&#61;KFunction2<Lines,RemoveFunction,Map<String,Int>>
typealiasNormalizeFunction&#61;KFunction2<Lines,ScanFunction,Map<String,Int>>
typealiasReadFunction&#61;KFunction2<Lines,NormalizeFunction,Map<String,Int>>funreadFile(filename:String,function:ReadFunction)&#61;function(read(filename),::normalize)

这是最终代码的摘录&#xff1a;

funrun(filename:String)&#61;(::readFile)(filename,::filterChars) (1)funreadFile(filename:String,function:ReadFunction)&#61;function(read(filename),::normalize) (2)funfilterChars(lines:List<String>,function:NormalizeFunction):Map<String,Int>{ (3)valpattern&#61;"\\W|_".toRegex()valfiltered&#61;lines.map{it.replace(pattern," ")}returnfunction(filtered,::scan) (3)
}

  1. 结合使用函数引用和invoke()的快捷方式运算符。 第二个参数是下一个要调用的函数上的函数引用
  2. 第二个参数的类型使用别名&#xff0c;以使代码更易于阅读。 它调用传递的function参数的invoke()方法&#xff0c;并传递下一个函数作为参考进行调用
  3. 其余的遵循相同的逻辑&#xff1a;使用高阶函数作为最后一个参数&#xff0c;并调用invoke()的快捷方式版本以继续链

结论

至于介绍&#xff0c;虽然类型有助于降低某些错误的可能性&#xff0c;但它们也会降低可读性。 幸运的是&#xff0c;Kotlin类型别名对此很有帮助。

call()invoke()是使用反射调用函数时要考虑的两个选项。 他们每个人都有优点和缺点。

这篇文章的完整源代码可以在Github上找到。

翻译自: https://blog.frankel.ch/exercises-programming-style/5/

高阶编程



推荐阅读
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文介绍了在Java中检查字符串是否仅包含数字的方法,包括使用正则表达式的示例代码,并提供了测试案例进行验证。同时还解释了Java中的字符转义序列的使用。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • switch语句的一些用法及注意事项
    本文介绍了使用switch语句时的一些用法和注意事项,包括如何实现"fall through"、default语句的作用、在case语句中定义变量时可能出现的问题以及解决方法。同时也提到了C#严格控制switch分支不允许贯穿的规定。通过本文的介绍,读者可以更好地理解和使用switch语句。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • java drools5_Java Drools5.1 规则流基础【示例】(中)
    五、规则文件及规则流EduInfoRule.drl:packagemyrules;importsample.Employ;ruleBachelorruleflow-group ... [详细]
author-avatar
多多之爱
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有