使用纯Java和函数式框架在您的Java应用程序中构建惰性

惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。首先,您可以将耗时的计算推迟到绝对需要的时候。其次,您可以创造无限个集合,只要它们继续收到请求,就会继续提供元素。第三,map 和 filter 等函数的惰性使用让您能够得到更高效的代码。Java 并没有为惰性提供原生支持,但一些框架和后继语言支持这种惰性,我会在本期和下期文章中探讨它们。

假定使用此伪">代码片段来打印列表的长度:

print length([2+1, 3*2, 1/0, 5-4])

如果您尝试执行此代码,结果会因为代码的编程语言类型的不同而有所不同:严格或不严格(也被称为惰性)。在严格的编程语言中,执行(或编译)此代码产生一个 DivByZero 异常,原因是列表的第三个元素。在不严格的语言中,其结果是 4,它准确地报告了列表中的项目数。毕竟,我调用的方法是 length(),而不是 lengthAndThrowExceptionWhenDivByZero()!Haskell 是为数不多的仍在使用的不严格语言。可惜的是,Java 不支持不严格的计算,但您仍然可以在 Java 中使用惰性的概念。

在 Java 中的惰性迭代器

Java 缺乏对惰性集合的原生支持,但这并不意味着您不能使用 Iterator 模拟一个惰性集合。在本系列的前几篇文章中,我使用了一个简单的素数算法来说明函数式概念。我会在 上期文章 中介绍的优化类的基础上展开本文的讨论,同时提供清单 1 中展示的增强:

清单 1. 确定素数的简单算法

import java.util.HashSet;import java.util.Set;import static java.lang.Math.sqrt;public class Prime { public static boolean isFactor(int potential, int number) { return number % potential == 0; } public static Set<Integer> getFactors(int number) { Set<Integer> factors = new HashSet<Integer>(); factors.add(1); factors.add(number); for (int i = 2; i < sqrt(number) + 1; i++) if (isFactor(i, number)) { factors.add(i); factors.add(number / i); } return factors; } public static int sumFactors(int number) { int sum = 0; for (int i : getFactors(number)) sum += i; return sum; } public static boolean isPrime(int number) { return number == 2 || sumFactors(number) == number + 1; } public static Integer nextPrimeFrom(int lastPrime) { lastPrime++; while (! isPrime(lastPrime)) lastPrime++; return lastPrime; }}

前面的一期文章 详细讨论了这个类是如何确定某个整数是否是素数的细节。在 清单 1 中,我添加了 nextPrimeFrom() 方法,根据输入的参数生成下一个素数。该方法在本文即将出现的示例中发挥了重要的作用。

一般情况下,开发人员认为迭代器会使用集合作为后备存储,但是支持 Iterator 接口的任何集合都符合这个条件。因此,我可以创建一个素数的无限迭代器,如清单 2 所示:

清单 2. 创建一个惰性迭代器

public class PrimeIterator implements Iterator<Integer> { private int lastPrime = 1; public boolean hasNext() { return true; } public Integer next() { return lastPrime = Prime.nextPrimeFrom(lastPrime); } public void remove() { throw new RuntimeException("Can't change the fundamental nature of the universe!"); }}

在 清单 2 中,hasNext() 方法始终返回 true,因为就我们目前所掌握的知识,素数的数量是无限的。remove() 方法在此处不适用,所以在意外调用情况下,会抛出一个异常。沉稳的做法是使用 next() 方法,它用一行代码处理两件事。第一,它调用我在 清单 1 中添加的 nextPrimeFrom() 方法,根据上一个素数生成下一个素数。第二,它利用了 Java 在单个语句中完成赋值与返回结果的能力,更新内部的 lastPrime 字段。我在清单 3 中执行惰性迭代器:

清单 3. 测试惰性迭代器

public class PrimeTest { private ArrayList<Integer> PRIMES_BELOW_50 = new ArrayList<Integer>() {{ add(2); add(3); add(5); add(7); add(11); add(13); add(17); add(19); add(23); add(29); add(31); add(37); add(41); add(43); add(47); }}; @Test public void prime_iterator() { Iterator<Integer> it = new PrimeIterator(); for (int i : PRIMES_BELOW_50) {
assertTrue(i == it.next()); } }}

在 清单 3中,我创建了一个 PrimeIterator,并验证它会报告前 50 个素数。虽然这不是迭代器的典型用法,但它模仿一些惰性集合的有用行为。

时间: 2024-09-20 03:21:35

使用纯Java和函数式框架在您的Java应用程序中构建惰性的相关文章

Java理论与实践: 应该在下一个企业应用程序中使用JMS吗?

最近几年,开发人员可以更广泛地得到企业消息排队(MQ)产品.适当地使 用 MQ 技术经常可以改善应用程序的组织.性能和可伸缩性.Java 消息服务 (Java Message Service (JMS))是集成到 J2EE 中的一部分,它使得 MQ 服务 可以为任何 J2EE 应用程序所用.在本文(也是本专栏系列的第一部分)中, Brian 概述了在 Java 应用程序中使用消息排队的一些好处,并探讨了能够从 MQ 技术中获益最大的问题类型.请在 论坛上(或者通过单击本文顶部或底部的 讨论)同作

使用Acegi保护Java应用程序,第5部分: 保护JSF应用程序中的JavaBean

JSF 应用程序中使用的 bean 的可配置安全性 这个 系列 由五部分组成,介绍了 Acegi Security System,并演示了如何 使用 Acegi 保护企业级 Java 应用程序.本文是该系列的最后一部分,将继续 讨论使用 Acegi 保护 JSF 应用程序.在 第 4 部分 中,我介绍了如何在不编 写 Java 代码的情况下使用 Acegi 保护 JSF 页面.我还详细说明了部署 JSF- Acegi 应用程序和用户访问该程序时发生的事件.在本部分中,我将着重介绍在 JSF 应用

详解Java的Struts框架中上传文件和客户端验证的实现_java

文件上传 Struts 2框架提供了内置支持处理文件上传使用基于HTML表单的文件上传.上传一个文件时,它通常会被存储在一个临时目录中,他们应该由Action类进行处理或移动到一个永久的目录,以确保数据不丢失. 请注意,服务器有一个安全策略可能会禁止写到目录以外的临时目录和属于web应用的目录. 在Struts中的文件上传是通过预先定义的拦截文件上传拦截器这是可通过org.apache.struts2.interceptor.FileUploadInterceptor类的defaultStack

使用七种不同的函数式框架和语言编写的一个示例

本系列的目标是重新调整您对函数式思维的认识,帮助您以全新的方式思考http://www.aliyun.com/zixun/aggregation/17253.html">常见问题,并寻找提升您的日常编码能力的方法.本系列文章将探讨函数编程概念.允许在 Java 语言中进行函数编程的框架.在 JVM 上运行的函数编程语言,以及语言设计的未来方向.本系列面向那些了解 Java 及其抽象工作原理,但对函数式语言不甚了解的开发人员. 函数式编程语言实现代码重用的方法与面向对象的语言不同,这个主题我

让JAVA 和 .NET框架共存

.net框架 原创作者:Ashish Banerjee 翻译整理:51DOTNET CLUB(WWW.51DOTNET.COM)SLASH 目的:对JAVA与.NET框架共存的可能性做一个评估 目标受众:JAVA程序员和系统工程师    提要:        首先是对JAVA 和 .NET平台的构成做一个分析,然后是我个人对JAVA如何形成的一个认识,接着是分析微软和SUN之间的合作与分歧,最后是JAVA与.NET合作的前景.      我个人强烈认为JAVA与.NET将在不久的未来逐步的统一起

是否能让JAVA 和 .NET框架共存(转)

.net框架 原创作者:Ashish Banerjee 翻译整理:51DOTNET CLUB(WWW.51DOTNET.COM)SLASH 目的:对JAVA与.NET框架共存的可能性做一个评估 目标受众:JAVA程序员和系统工程师    提要:        首先是对JAVA 和 .NET平台的构成做一个分析,然后是我个人对JAVA如何形成的一个认识,接着是分析微软和SUN之间的合作与分歧,最后是JAVA与.NET合作的前景.      我个人强烈认为JAVA与.NET将在不久的未来逐步的统一起

Jt —— 面向Java模式的框架

概述 Jt 是一种用于快速实现 Java 应用程序的设计模式框架.Jt 在许多大的任务关键型系统中有应用.该框架实现以下目标: 框架架构基于一个消息传送设计模式:框架组件能够交互信息并通过发送.接收和处理消息执行计算.一个消息传送 API 具有简易性.强大的封装性和松耦合特性:可以使用一个 "lego/messaging" 架构将框架组件交换地插入复杂的框架应用程序中.可对框架消息执行同步或异步处理.框架充分利用消息设计模式/API 的功能和简易性. 设计模式框架使用消息传送来实现和/

Java的Spring框架中AOP项目的一般配置和部署教程_java

0.关于AOP面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring框架中的一个重要内容.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. AOP是OOP的延续. 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等. 主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对

Java Fork Join 框架(四)性能

原文 http://gee.cs.oswego.edu/dl/papers/fj.pdf   作者:Doug Lea   译者:萧欢 4性能 如今,随着编译器与Java虚拟机性能的不断提升,性能测试结果也仅仅只能适用一时.但是,本节中所提到的测试结果数据却能揭示Fork/join框架的基本特性. 下面表格中简单介绍了在下文将会用到的一组fork/join测试程序.这些程序是从util.concurrent包里的示例代码改编而来,用来展示fork/join框架在解决不同类型的问题模型时所表现的差异