javaslang_使用Javaslang的Java 8中的功能数据结构

javaslang

Java 8的lambda(λ)使我们能够创建出色的API。 它们极大地提高了语言的表达能力。

Javaslang利用lambda来基于功能模式创建各种新功能。 其中之一是功能性集合库,旨在替代Java的标准集合。

(这只是鸟瞰图,您会在下面找到易于理解的版本。)

(这只是鸟瞰图,您将在下面找到易于理解的版本。)

功能编程

在深入探讨有关数据结构的细节之前,我想谈一些基本知识。 这将清楚说明为什么我创建Javaslang以及专门创建新的Java集合。

副作用

Java应用程序通常有很多副作用 。 他们改变了某种状态,也许是外部世界。 常见的副作用是在适当位置更改对象或变量,打印到控制台,写入日志文件或数据库。 如果副作用以不希望的方式影响我们程序的语义,则认为它们是有害的

例如,如果一个函数抛出一个异常并解释了该异常,则它被认为是影响我们程序的副作用。 此外, 异常类似于非本地goto语句 。 他们打破了正常的控制流程。 但是,实际应用程序确实会产生副作用。

int divide(int dividend, int divisor) {// throws if divisor is zeroreturn dividend / divisor;
}

在功能设置中,我们处于有利的情况下,可以在Try中封装副作用:

// = Success(result) or Failure(exception)
Try<Integer> divide(Integer dividend, Integer divisor) {return Try.of(() -> dividend / divisor);
}

此版本的除法不再抛出。 通过使用尝试类型,我们明确了可能的故障。

马里奥-富斯科可变性

参照透明

如果某个函数可以用其值替换而不影响程序的行为,则该函数或更一般的表达式称为“ 引用透明” 。 简单地说,给定相同的输入,输出总是相同的。

// not referential transparent
Math.random();// referential transparent
Math.max(1, 2);

如果涉及的所有表达式都是引用透明的,则该函数称为纯函数。 由纯函数组成的应用程序在编译后很可能就可以正常工作 。 我们能够对此进行推理。 单元测试易于编写,并且调试已成为过去。

价值观思考

Clojure的创建者Rich Hickey就“价值的价值”进行了精彩的演讲。 最有趣的值是不可变值。 主要原因是价值不变

  • 本质上是线程安全的,因此不需要同步
  • 对于equalshashCode稳定,因此是可靠的哈希键
  • 不需要克隆
  • 在未经检查的协变强制转换中使用时,表现为类型安全(特定于Java)

改进Java的关键是使用不可变的值引用透明函数配对。

Javaslang提供了必要的控件和集合,以实现日常Java编程中的这一目标。

简而言之,数据结构

Javaslang的集合库由建立在lambda之上的一组丰富的功能数据结构组成。 他们与Java原始集合共享的唯一接口是Iterable。 主要原因是Java的collection接口的mutator方法不返回基础collection类型的对象。

通过查看不同类型的数据结构,我们将了解为什么如此重要。

可变数据结构

Java是一种面向对象的编程语言。 我们将状态封装在对象中以实现数据隐藏,并提供更改器方法来控制状态。 Java集合框架(JCF​​)就是基于这个想法而建立的。

interface Collection<E> {// removes all elements from this collectionvoid clear();
}

今天,我领悟到一种无效的返回类型是一种气味。 有证据表明发生了副作用 ,状态发生了变化。 共享的可变状态不仅是并发设置,而且是失败的重要原因。

不变的数据结构

不变的数据结构在创建后无法修改。 在Java上下文中,它们以集合包装的形式广泛使用。

List<String> list = Collections.unmodifiableList(otherList);// Boom!
list.add("why not?");

有许多库为我们提供了类似的实用程序方法。 结果始终是特定集合的不可修改视图。 通常,当我们调用mutator方法时,它将在运行时抛出。

持久数据结构

持久数据结构在被修改时会保留其自身的先前版本,因此实际上是不可变的。 完全持久的数据结构允许在任何版本上进行更新和查询。

许多操作仅执行很小的更改。 仅复制以前的版本是没有效率的。 为了节省时间和内存,至关重要的是确定两个版本之间的相似性并共享尽可能多的数据。

该模型没有施加任何实现细节。 功能数据结构在这里发挥作用。

功能数据结构

也被称为功能数据结构 ,它们是不可变的持久的 。 功能数据结构的方法是参照透明的

Javaslang具有各种最常用的功能数据结构。 以下示例将进行深入说明。

链表

最受欢迎的也是最简单的功能数据结构之一是(单)链接List 。 它具有元素和元素列表。 链接列表的行为类似于遵循后进先出(LIFO)方法的堆栈。

在Javaslang中,我们实例化一个List像这样:

// = List(1, 2, 3)
List<Integer> list1 = List.of(1, 2, 3);

每个List元素形成一个单独的List节点。 最后一个元素的尾部为Nil,即空列表。

清单1

这使我们能够在列表的不同版本之间共享元素。

// = List(0, 2, 3)
List<Integer> list2 = list1.tail().prepend(0);

新的head元素0 链接到原始List的尾部。 原始列表保持不变。

list2

这些操作在恒定的时间内发生,换句话说,它们与List的大小无关。 其他大多数操作都需要线性时间。 在Javaslang中,这是由接口LinearSeq表示的,我们可能已经从Scala知道了。

如果我们需要可在恒定时间内查询的数据结构,则Javaslang提供了Array和Vector。 两者都具有随机访问功能。

数组类型由对象的Java数组支持。 插入和删除操作花费线性时间。 向量在数组和列表之间。 它在随机访问和修改这两个方面都表现出色。

实际上,链接列表也可以用于实现Queue数据结构。

队列

可以基于两个链接列表来实现非常有效的功能队列。 前一个 List包含已出队的元素, 后一个 List包含已 的元素。 入队和出队两个操作均在O(1)中执行。

Queue<Integer> queue = Queue.of(1, 2, 3).enqueue(4).enqueue(5);

初始队列由三个元素创建。 后面的列表上有两个元素。

队列1

如果在出队时前面的List用完了元素,那么后面的List将被反转并成为新的前面的List。

队列2

使一个元素出队时,我们得到一对第一个元素和剩余的Queue。 因为功能数据结构是不可变的且持久的,所以有必要返回新版本的Queue。 原始队列不受影响。

Queue<Integer> queue = Queue.of(1, 2, 3);// = (1, Queue(2, 3))
Tuple2<Integer, Queue<Integer>> dequeued =queue.dequeue();

队列为空时会发生什么? 然后dequeue()将引发NoSuchElementException。 要以功能性的方式来实现它,我们宁愿期望一个可选结果。

// = Some((1, Queue()))
Queue.of(1).dequeueOption();// = None
Queue.empty().dequeueOption();

不管是否为空,都可以进一步处理可选结果。

// = Queue(1)
Queue<Integer> queue = Queue.of(1);// = Some((1, Queue()))
Option<Tuple2<Integer, Queue<Integer>>>dequeued = queue.dequeueOption();// = Some(1)
Option<Integer> element =dequeued.map(Tuple2::_1);// = Some(Queue())
Option<Queue<Integer>> remaining =dequeued.map(Tuple2::_2);

排序集

排序集是比队列更常用的数据结构。 我们使用二分搜索树来对它们进行功能化建模。 这些树由最多具有两个子节点的节点组成,每个节点处都有值。

我们在有序的情况下(由元素Comparator表示)构建二进制搜索树。 任何给定节点的左子树的所有值都严格小于给定节点的值。 正确的子树的所有值都严格大于。

// = TreeSet(1, 2, 3, 4, 6, 7, 8)
SortedSet<Integer> xs =TreeSet.of(6, 1, 3, 2, 4, 7, 8);

二叉树1

对此类树的搜索以O(log n)时间运行。 我们从根开始搜索,并确定是否找到了元素。 由于这些值的总顺序,我们知道下一步要在当前树的左侧或右侧分支中搜索的位置。

// = TreeSet(1, 2, 3);
SortedSet<Integer> set = TreeSet.of(2, 3, 1, 2);// = TreeSet(3, 2, 1);
Comparator<Integer> c = (a, b) -> b - a;
SortedSet<Integer> reversed =TreeSet.of(c, 2, 3, 1, 2);

大多数树操作本质上都是递归的 。 插入功能的行为类似于搜索功能。 当到达搜索路径的末尾时,将创建一个新节点,并将整个路径重建到根。 尽可能引用现有的子节点。 因此,插入操作需要O(log n)的时间和空间。

// = TreeSet(1, 2, 3, 4, 5, 6, 7, 8)
SortedSet<Integer> ys = xs.add(5);

二叉树2

为了维持二叉搜索树的性能特征,需要保持平衡。 从根到叶的所有路径都必须具有大致相同的长度。

在Javaslang中,我们基于Red / Black Tree实现了二叉搜索树 。 它使用特定的着色策略来使树在插入和删除时保持平衡。 要了解有关此主题的更多信息,请参阅Chris Okasaki的《 Purely Functional Data Structures》 。

收藏状态

通常,我们正在观察编程语言的融合。 好的功能使它消失,其他消失。 但是Java是不同的,它永远是向后兼容的。 这是一种优势,但也会减缓发展。

Lambda使Java和Scala更加紧密地联系在一起,但是它们仍然如此不同。 Scala的创建者Martin Odersky最近在他的BDSBTB 2015主题演讲中提到了Java 8集合的状态。

他将Java的Stream描述为迭代器的一种奇特形式。 Java 8 Stream API是提升集合的示例。 它的作用是定义一个计算并将其链接到另一个专有步骤中的特定集合。

// i + 1
i.prepareForAddition().add(1).mapBackToInteger(Mappers.toInteger())

这就是新的Java 8 Stream API的工作方式。 它是众所周知的Java集合之上的计算层。

// = ["1", "2", "3"] in Java 8
Arrays.asList(1, 2, 3).stream().map(Object::toString).collect(Collectors.toList())

Javaslang受到Scala的极大启发。 这就是上面的示例在Java 8中的样子。

// = Stream("1", "2", "3") in Javaslang
Stream.of(1, 2, 3).map(Object::toString)

在过去的一年中,我们为实现Javaslang集合库付出了很多努力。 它包含使用最广泛的收集类型。

顺序

我们通过实现顺序类型开始了自己的旅程。 我们已经在上面描述了链接列表。 流,然后是一个懒惰的链表。 它使我们可以处理可能无限长的元素序列。

集合序列

所有集合都是可迭代的,因此可以在增强的for语句中使用。

for (String s : List.of("Java", "Advent")) {// side effects and mutation
}

我们可以通过内部化循环并使用lambda注入行为来实现相同目的。

List.of("Java", "Advent").forEach(s -> {// side effects and mutation
});

无论如何,正如我们之前所看到的,我们更喜欢返回值的表达式而不是什么都不返回的语句。 通过看一个简单的示例,很快我们将认识到语句增加了噪音,并将属于的内容分开。

String join(String... words) {StringBuilder builder = new StringBuilder();for(String s : words) {if (builder.length() > 0) {builder.append(", ");}builder.append(s);}return builder.toString();
}

Javaslang集合为我们提供了许多对底层元素进行操作的功能。 这使我们能够以一种非常简洁的方式表达事物。

String join(String... words) {return List.of(words).intersperse(", ").fold("", String::concat);
}

大多数目标可以使用Javaslang以各种方式实现。 在这里,我们将整个方法主体简化为List实例上的流畅函数调用。 我们甚至可以删除整个方法,然后直接使用List获取计算结果。

List.of(words).mkString(", ");

在现实世界的应用程序中,我们现在能够大幅度减少代码行数,从而降低错误的风险。

设置并映射

顺序很棒。 但是,为了完整起见,集合库还需要不同类型的“集合”和“地图”。

收藏集地图

我们描述了如何使用二叉树结构对排序集进行建模。 排序的Map就是包含键值对并具有键顺序的排序Set。

HashMap实现由哈希数组映射树(HAMT)支持 。 因此,HashSet由包含密钥对的HAMT支持。

我们的地图具有特殊的条目类型来表示键值对。 相反,我们使用已经是Javaslang一部分的Tuple2。 元组的字段被枚举。

// = (1, "A")
Tuple2<Integer, String> entry = Tuple.of(1, "A");Integer key = entry._1;
String value = entry._2;

Maps和Tuples在整个Javaslang中使用。 元组不可避免地会以一般方式处理多值返回类型。

// = HashMap((0, List(2, 4)), (1, List(1, 3)))
List.of(1, 2, 3, 4).groupBy(i -> i % 2);// = List((a, 0), (b, 1), (c, 2))
List.of('a', 'b', 'c').zipWithIndex();

在Javaslang,我们通过实现99欧拉问题探索和测试我们的库。 这是一个很好的概念证明。 请不要犹豫,发送请求请求。

动手!

我真的希望本文能引起您对Javaslang的兴趣。 即使像我一样在工作中使用Java 7(或更低版本),也可以遵循函数式编程的思想。 这将是非常好的!

请确保Javaslang在2016年成为工具带的一部分。

骇客骇客!

PS:有问题吗? @_Javaslang或Gitter聊天

翻译自: https://www.javacodegeeks.com/2015/12/functional-data-structures-java-8-javaslang.html

javaslang

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336481.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java调用kafka接口发送数据_Java调用Kafka生产者,消费者Api及相关配置说明

本次的记录内容包括&#xff1a;1.Java调用生产者APi流程2.Kafka生产者Api的使用及说明3.Kafka消费者Api的使用及说明4.Kafka消费者自动提交Offset和手动提交Offset5.自定义生产者的拦截器&#xff0c;分区器那么接下来我就带大家熟悉以上Kafka的知识说明1.Java调用生产者APi流…

java如何模拟请求_单元测试如何模拟用户请求

python web自动化测试设计构工具书40.9元包邮(需用券)去购买 >错误正当我高高兴兴写完后台c层的测试代码准备提交时&#xff0c;测试机器人报了很多401错误&#xff0c;把代码拉下来一看&#xff0c;原来当我写代码时&#xff0c;我的伙伴已经写好后台的拦截器了&#xff0c…

LeetCode 83. 删除排序链表中的重复元素

原题链接 解法&#xff1a;通过一个指针从头到尾进行扫描 class Solution { public:ListNode* deleteDuplicates(ListNode* head) {if(!head)return nullptr;auto p1 head;while(p1->next){if(p1->next->val p1->val)p1->nextp1->next->next;else p1 …

后端 java ee_刷新器-Java EE 7后端十大功能

后端 java ee这是我的小型Java EE 7复习系列的第二部分。 在进行了简要概述的第一篇介绍之后&#xff0c;我决定请Arjan Tijms撰写有关Java EE 7中他最喜欢的后端新功能的信息。如果您关注Java EE领域&#xff0c;您将会知道Arjan。 他是Java EE开发人员&#xff0c;JSF和Secur…

java cucumber_为Java + STANDARD值引入Cucumber

java cucumber作为软件开发人员&#xff0c;我们都有最喜欢的工具来使我们成功。 许多人在开始工作时就很适合这份工作&#xff0c;但很快就不见了。 其他人则需要太多的设置和培训才能“将脚趾浸入水中”&#xff0c;只是为了简单地确定它们是否是正确的工具即可。 Cucumber …

文章id 文章标题点击量php,WordPress如何通过文章ID获取文章标题等信息

如果我们想要在某一个主题的php文件中调用文章的标题&#xff0c;内容等信息&#xff0c;而在WordPress中唯一一直不会改变的就是文章发布时生成的ID&#xff0c;我们只需要获取文章的ID&#xff0c;即可通过文章ID来获取我们想要的文章信息。调用方法php$id // 文章的 id$tit…

javaone_JavaOne 2015:高级模块化开发

javaoneJavaOne 2015看到了Project Jigsaw团队关于Java 9中的模块化的一系列讨论 。它们都是非常有趣的&#xff0c;并且充满了宝贵的信息&#xff0c;我敦促每个Java开发人员都注意它们。 除此之外&#xff0c;我想给社区一种搜索和引用它们的方法&#xff0c;因此我在这里总…

spark rest_Spark简介,您的下一个REST Java框架

spark rest我希望您今年Java来了&#xff01; 今天&#xff0c;我们将研究一个清新&#xff0c;简单&#xff0c;美观且实用的框架&#xff0c;以Java编写REST应用程序。 它将非常简单&#xff0c;甚至根本不会看起来像Java。 我们将研究Spark Web框架。 不&#xff0c;它与Ap…

oracle 授权 增删改查权限_Oracle增删改查与函数

SQL -- 结构化查询语言 关系型数据库分类&#xff1a; DDL DML DCL DQL TCL Oracle 的数据类型&#xff1a;字符 char() varchar2()数字 number(p,s)时间 date timestamp 文件 clob blob 二维表 table 创建表 CREATE create table 表名 ( 列名 数据类型 [约束], 列名 类型 ... …

_用WSL,MobaXterm,Cmder配置linux开发环境

离不开Windows的理由很多,作为后端开发需要使用linux的情况也很多,双系统总归是不方便,而且linux下的GUI体验也没用Win 10好. 如果使用虚拟机,那么文件交换和网络等各种问题也需要解决,对系统的内存要求也更高一些.微软为了让更多的开发人员留在Win10上面,开发了WSL功能.目前的…

php中上传图片怎么显示出来,PHP上传图片类显示缩略图功能

有缩略图功能 但是 感觉不全面&#xff0c;而且有点问题&#xff0c;继续学习&#xff0c;将来以后修改下/*** Created by PhpStorm.* User: Administrator* Date: 2016/6/28* Time: 21:04*/class upload{protected $fileMine;//文件上传类型protected $filepath;//文件上传路径…

javaparser_JavaParser入门:以编程方式分析Java代码

javaparser我最喜欢的事情之一是解析代码并对其执行自动操作。 因此&#xff0c;我开始为JavaParser做出贡献&#xff0c;并创建了两个相关项目&#xff1a; java-symbol-solver和Effectivejava 。 作为JavaParser的贡献者&#xff0c;我反复阅读了一些有关从Java源代码提取信…

wps xml转换表格_这功能WPS卖近百元?教你免费将PDF转成Word

[PConline 应用]PDF文件如何转换成为Word&#xff1f;很多朋友研究这个问题已经很久了&#xff0c;PDF更利于统一格式传播&#xff0c;Word更便于编辑&#xff0c;因此收到PDF文件后、想要修改时要如何将PDF转换成Word可谓是一个刚需。当然&#xff0c;不少办公软件提供了这样的…

睡眠 应该用 a加权 c加权_在神经网络中提取知识:学习用较小的模型学得更好...

在传统的机器学习中&#xff0c;为了获得最先进的(SOTA)性能&#xff0c;我们经常训练一系列整合模型来克服单个模型的弱点。 但是&#xff0c;要获得SOTA性能&#xff0c;通常需要使用具有数百万个参数的大型模型进行大量计算。 SOTA模型(例如VGG16 / 19&#xff0c;ResNet50)…

gpu编程如何一步步学习_如何学习贴片机编程

学习贴片机编程首选要对贴片机有所熟悉了解&#xff0c;另外对常用的电脑编辑软件要会使用。目前通常学习贴片机编程有专门的培训学校&#xff0c;或者跟着生产线上现有的贴片机编程师傅学习熟练后再进行编程操作。下面深圳智驰科技就来分享一下如何学习贴片机编程。对贴片机编…

plotcylinder matlab,Matlab在任意两点之间绘制三维圆柱

Matlab在任意两点之间绘制三维圆柱Matlab在任意两点之间绘制三维圆柱此函数可能存在一些不足&#xff0c;请多多指教&#xff01;function plotcylinder(u1,u2,color_a,r)Lnorm(u1-u2);RODu2-u1;[X,Y,Z]cylinder(r,100);x1X*0;y1Y*0;z1Z*0;ZL*Z-L/2;ROD_midpoint(u1u2)/2;xROD_…

jdk8和hotspot_HotSpot的-XshowSettings标志的简单性和价值

jdk8和hotspot一个方便的HotSpot JVM标志 &#xff08; 选项为Java启动 java &#xff09;是-XshowSettings选项。 Oracle Java启动器描述页面中对此选项进行了如下描述 &#xff1a; -XshowSettings &#xff1a; category显示设置并继续。 该选项的可能类别参数包括&#xf…

matlab信号分割与比对,matlab测量计算信号的相似度

本示例说明如何测量信号相似度。将回答以下问题&#xff1a;如何比较具有不同长度或不同采样率的信号&#xff1f;如何确定测量中是否存在信号或仅有噪声&#xff1f;有两个信号相关吗&#xff1f;如何测量两个信号之间的延迟&#xff1f;比较具有不同采样率的信号考虑一个音频…

Spring Bootstrap中具有配置元数据的高级配置

在简要介绍了配置元数据并涵盖了我之前的文章《 在Spring Boot中使用配置元数据Pimp您的配置》中的基础知识之后&#xff0c;现在该看看如何进一步执行此步骤并进一步自定义配置。 在这篇文章中&#xff0c;我计划提出对配置属性的弃用&#xff0c;并讨论各种值提供程序&#x…

ssh 与 telnet 有何不同?_采用创新面料Nike Infinalon的全新瑜珈系列究竟有何不同?...

采用创新面料Nike Infinalon的全新瑜珈系列究竟有何不同&#xff1f;无拘无束自由运动——这是耐克瑜伽系列新品的核心设计理念。全新系列为你提供垫上瑜伽时毫无束缚的舒适感&#xff0c;采用了耐克创新型面料&#xff1a;Nike Infinalon。Nike Infinalon应用于耐克最新瑜伽系…