Page tree
Skip to end of metadata
Go to start of metadata

Recently Updated


BLOG OSSEZ 博客内容更新

HoneyMoose
HoneyMoose 的清新小站
Spring Batch 批量处理策略
为了帮助设计和实现批量处理系统,基本的批量应用是通过块和模式来构建的,同时也应该能够为程序开发人员和设计人员提供结构的样例和基础的批量处理程序。 当你开始设计一个批量作业任务的时候,商业逻辑应该被拆分一系列的步骤,而这些步骤又是可以通过下面的标准构件块来实现的: 转换应用程序(Conversion Applications):针对每一个从外部系统导出或者提供的各种类型的文件,我们都需要创建一个转换应用程序来讲这些类型的文件和数据转换为处理所需要的标准格式。这个类型的批量应用程序可以是正规转换工具模块中的一部分,也可以是整个的转换工具模块(请查看:基本的批量服务(Basic Batch Services))。 校验应用程序(Validation Applications):校验应用程序能够保证所有的输入和输出记录都是正确和一致的。校验通常是基于头和尾进行校验的,校验码和校验算法通常是针对记录的交叉验证。 提取应用(Extract Applications): 这个应用程序通常被用来从数据库或者文本文件中读取一系列的记录,并对记录的选择通常是基于预先确定的规则,然后将这些记录输出到输出文件中。 提取/更新应用(Extract/Update Applications):这个应用程序通常被用来从数据库或者文本文件中读取记录,并将每一条读取的输入记录更新到数据库或者输出数据库中。 处理和更新应用(Processing and Updating Applications):这种程序对从提取或验证程序 传过来的输入事务记录进行处理。这处理通常包括有读取数据库并且获得需要处理的数据,为输出处理更新数据库或创建记录。 输出和格式化应用(Output/Format Applications):一个应用通过读取一个输入文件,对输入文件的结构重新格式化为需要的标准格式,然后创建一个打印的输出文件,或将数据传输到其他的程序或者系统中。 更多的,一个基本的应用外壳应该也能够被针对商业逻辑来提供,这个外壳通常不能通过上面介绍的这些标准模块来完成。 另外的一个主要的构建块,每一个引用通常可以使用下面的一个或者多个标准工具步骤,例如: 分类(Sort)- 一个程序可以读取输入文件后生成一个输出文件,在这个输出文件中可以对记录进行重新排序,重新排序的是根据给定记录的关键字段进行重新排序的。分类通常使用标准的系统工具来执行。 拆分(Split)- 一个程序可以读取输入文件后,根据需要的字段值,将输入的文件拆分为多个文件进行输出。拆分通常使用标准的系统工具来执行。 合并(Merge)- 一个程序可以读取多个输入文件,然后将多个输入文件进行合并处理后生成为一个单一的输出文件。合并可以自定义或者由参数驱动的(parameter-driven)系统实用程序来执行. 批量处理应用程序可以通过下面的输入数据类型来进行分类: 数据库驱动应用程序(Database-driven applications)可以通过从数据库中获得的行或值来进行驱动。 文件驱动应用程序(File-driven applications) 可以通过从文件中获得的数据来进行驱动。 消息驱动应用程序(Message-driven applications) 可以通过从消息队列中获得的数据来进行驱动。 所有批量处理系统的处理基础都是策略(strategy)。对处理策略进行选择产生影响的因素包括有:预估批量处理需要处理的数据量,在线并发量,和另外一个批量处理系统的在线并发量,可用的批量处理时间窗口(很多企业都希望系统是能够不间断运行的,基本上来说批量处理可能没有处理时间窗口)。 针对批量处理的标准处理选项包括有: 在一个批处理窗口中执行常规离线批处理 并发批量 / 在线处理 并发处理很多不同的批量处理或者有很多批量作业在同一时间运行 分区(Partitioning),就是在同一时间有很多示例在运行相同的批量作业 混合上面的一些需求 上面列表中的顺序代表了批处理实现复杂性的排序,在同一个批处理窗口的处理最简单,而分区实现最复杂。 上面的一些选项或者所有选项能够被商业的任务调度所支持。 在下面的部分,我们将会针对上面的处理选项来对细节进行更多的说明。需要特别注意的是,批量处理程序使用提交和锁定策略将会根据批量处理的不同而有所不同。作为最佳实践,在线锁策略应该使用相同的原则。因此,在设计批处理整体架构时不能简单地拍脑袋决定,需要进行详细的分析和论证。 锁定策略可以仅仅使用常见的数据库锁或者你也可以在系统架构中使用其他的自定义锁定服务。这个锁服务将会跟踪数据库的锁(例如在一个专用的数据库表(db-table)中存储必要的信息),然后在应用程序请求数据库操作时授予权限或拒绝。重试逻辑应该也需要在系统架构中实现,以避免批量作业中的因资源锁定而导致批量任务被终止。 批量处理作业窗口中的常规处理 针对运行在一个单独批处理窗口中的简单批量处理,更新的数据对在线用户或其他批处理来说并没有实时性要求,也没有并发问题,在批处理运行完成后执行单次提交即可。 大多数情况下,一种更健壮的方法会更合适.要记住的是,批处理系统会随着时间的流逝而增长,包括复杂度和需要处理的数据量。如果没有合适的锁定策略,系统仍然依赖于一个单一的提交点,则修改批处理程序会是一件痛苦的事情。 因此,即使是最简单的批处理系统,也应该为重启-恢复(restart-recovery)选项考虑提交逻辑。针对下面的情况,批量处理就更加复杂了。 并发批量 / 在线处理 批处理程序处理的数据如果会同时被在线用户实时更新,就不应该锁定在线用户需要的所有任何数据(不管是数据库还是文件),即使只需要锁定几秒钟的时间。 还应该每处理一批事务就提交一次数据库。这减少了其他程序不可用的数据数据量,也压缩了数据不可用的时间。 另一个可以使用的方案就是使用逻辑行基本的锁定实现来替代物理锁定。通过使用乐观锁(Optimistic Locking )或悲观锁(Pessimistic Locking)模式。 乐观锁假设记录争用的可能性很低。这通常意味着并发批处理和在线处理所使用的每个数据表中都有一个时间戳列。当程序读取一行进行处理时,同时也获得对应的时间戳。当程序处理完该行以后尝试更新时,在 update 操作的 WHERE 子句中使用原来的时间戳作为条件.如果时间戳相匹配,则数据和时间戳都更新成功。如果时间戳不匹配,这表明在本程序上次获取和此次更新这段时间内已经有另一个程序修改了同一条记录,因此更新不会被执行。 悲观锁定策略假设记录争用的可能性很高,因此在检索时需要获得一个物理锁或逻辑锁。有一种悲观逻辑锁在数据表中使用一个专用的 lock-column 列。当程序想要为更新目的而获取一行时,它在 lock column 上设置一个标志。如果为某一行设置了标志位,其他程序在试图获取同一行时将会逻辑上获取失败。当设置标志的程序更新该行时,它也同时清除标志位,允许其他程序获取该行。请注意,在初步获取和初次设置标志位这段时间内必须维护数据的完整性,比如使用数据库锁(例如,SELECT FOR UPDATE)。还请注意,这种方法和物理锁都有相同的缺点,除了它在构建一个超时机制时比较容易管理。比如记录而用户去吃午餐了,则超时时间到了以后锁会被自动释放。 这些模式并不一定适用于批处理,但他们可以被用在并发批处理和在线处理的情况下(例如,数据库不支持行级锁)。作为一般规则,乐观锁更适合于在线应用,而悲观锁更适合于批处理应用。只要使用了逻辑锁,那么所有访问逻辑锁保护的数据的程序都必须采用同样的方案。 请注意:这两种解决方案都只锁定(address locking)单条记录。但很多情况下我们需要锁定一组相关的记录。如果使用物理锁,你必须非常小心地管理这些以避免潜在的死锁。如果使用逻辑锁,通常最好的解决办法是创建一个逻辑锁管理器,使管理器能理解你想要保护的逻辑记录分组(groups),并确保连贯和没有死锁(non-deadlocking)。这种逻辑锁管理器通常使用其私有的表来进行锁管理、争用报告、超时机制 等等。 并行处理 并行处理允许多个批量处理运行(run)/任务(job)同时并行地运行。以使批量处理总运行时间降到最低。如果多个任务不使用相同的文件、数据表、索引空间时,批量处理这些不算什么问题。如果确实存在共享和竞争,那么这个服务就应该使用分区数据来实现。另一种选择是使用控制表来构建一个架构模块以维护他们之间的相互依赖关系。控制表应该为每个共享资源分配一行记录,不管这些资源是否被某个程序所使用。执行并行作业的批处理架构或程序随后将查询这个控制表,以确定是否可以访问所需的资源。 如果解决了数据访问的问题,并行处理就可以通过使用额外的线程来并行实现。在传统的大型主机环境中,并行作业类上通常被用来确保所有进程都有充足的 CPU 时间。无论如何,解决方案必须足够强劲,以确保所有正在运行的进程都有足够的运行处理时间。 并行处理的其他关键问题还包括负载平衡以及一般系统资源的可用性(如文件、数据库缓冲池等)。请注意,控制表本身也可能很容易变成一个至关重要的资源(有可能发生严重竞争)。 分区 分区技术允许多版本的大型批处理程序并发地(concurrently)运行。这样做的目的是减少超长批处理作业过程所需的时间。 可以成功分区的过程主要是那些可以拆分的输入文件 和/或 主要的数据库表被分区以允许程序使用不同的数据来运行。 此外,被分区的过程必须设计为只处理分配给他的数据集。分区架构与数据库设计和数据库分区策略是密切相关的。请注意,数据库分区并不一定指数据库需要在物理上实现分区,尽管在大多数情况下这是明智的。 下面的图片展示了分区的方法: 上图: 分区处理 系统架构应该足够灵活,以允许动态配置分区的数量。自动控制和用户配置都应该纳入考虑范围。自动配置可以根据参数来决定,例如输入文件大小 和/或 输入记录的数量。 分区方案 面列出了一些可能的分区方案,至于具体选择哪种分区方案,要根据具体情况来确定: 固定和均衡拆分记录集 这涉及到将输入的记录集合分解成均衡的部分(例如,拆分为 10 份,这样每部分是整个数据集的十分之一)。每个拆分的部分稍后由一个批处理/提取程序实例来处理。 为了使用这种方案,需要在预处理时候就将记录集进行拆分。拆分的结果有一个最大值和最小值的位置,这两个值可以用作限制每个 批处理/提取程序处理部分的输入。 预处理可能有一个很大的开销,因为它必须计算并确定的每部分数据集的边界。 通过关键字段(Key Column)拆分 这涉及到将输入记录按照某个关键字段来拆分,比如一个地区代码(location code),并将每个键分配给一个批处理实例。为了达到这个目标,也可以使用列值。 通过分区表来指派给一个批量处理实例 请查看下面的详细说明。 在使用这种方法时, 新值的添加将意味着需要手动重新配置批处理/提取程序,以确保新值被添加到某个特定的实例。 通过数据的部分值指派给一个批量处理实例 例如,值 0000-0999, 1000 – 1999, 等。 使用这种方法的时候,将确保所有的值都会被某个批处理作业实例处理到。然而,一个实例处理的值的数量依赖于列值的分布(即可能存在大量的值分布在0000-0999范围内,而在1000-1999范围内的值却很少)。如果使用这种方法,设计时应该考虑到数据范围的切分。 使用 通过分区表来指派 和 通过数据的部分值, 在这两种方法中,并不能将指定给批处理实例的记录实现最佳均匀分布。批处理实例的数量并不能动态配置。 通过视图(Views) 这种方法基本上是根据键列来分解,但不同的是在数据库级进行分解。它涉及到将记录集分解成视图。这些视图将被批处理程序的各个实例在处理时使用。分解将通过数据分组来完成。 使用这个方法时,批处理的每个实例都必须为其配置一个特定的视图(而非主表)。当然,对于新添加的数据,这个新的数据分组必须被包含在某个视图中。也没有自动配置功能,实例数量的变化将导致视图需要进行相应的改变。 附加的处理识别器 这涉及到输入表一个附加的新列,它充当一个指示器。在预处理阶段,所有指示器都被标志为未处理。在批处理程序获取记录阶段,只会读取被标记为未处理的记录,一旦他们被读取(并加锁),它们就被标记为正在处理状态。当记录处理完成,指示器将被更新为完成或错误。批处理程序的多个实例不需要改变就可以开始,因为附加列确保每条纪录只被处理一次。 使用该选项时,表上的I/O会动态地增长。在批量更新的程序中,这种影响被降低了,因为写操作是必定要进行的。 提取表到无格式文件 这包括将表中的数据提取到一个文件中。然后可以将这个文件拆分成多个部分,作为批处理实例的输入。 使用这个选项时,将数据提取到文件中,并将文件拆分的额外开销,有可能抵消多分区处理(multi-partitioning)的效果。可以通过改变文件分割脚本来实现动态配置。 With this option, the additional overhead of extracting the table into a […]
Spring Batch 基本的批处理指导原则
下面是一些关键的指导原则,可以在构批量处理解决方案可以参考: 请记住,通常皮脸处理体系结构将会影响在线应用的体系结构,同时反过来也是一样的。在你为批量任务和在线应用进行设计架构和环境的时候请尽可能的使用公共的模块。 越简单越好,尽量在一个单独的批量应用中构建简单的批量处理,并避免复杂的逻辑结构。 尽量的保持存储的数据和进程存储在同一个地方(换句话说就是尽量将数据保存到你程序运行的地方)。 最小化系统资源的使用,尤其针对 I/O。尽量在内存中执行尽可能多的操作。 检查应用的 I/O(分析 SQL 语句)来避免不必要的的物理 I/O 使用。特别是以下四个常见的缺陷(flaws)需要避免: 在数据可以只读一次就可以缓存起来的情况下,针对每一个事务都来读取数据 多次读取/查询同一事务中已经读取过的数据 产生不必要的表格或者索引扫描 在 SQL 查询中不指定 WHERE 查询的值。 在批量运行的时候不要将一件事重复 2 次。例如,如果你需要针对你需要报表的数据汇总,请在处理每一条记录时使用增量来存储,尽可能不要再去遍历一次同样的数据。 为批量进程在开始的时候就分配足够的内存,以避免在运行的时候再次分配内存。 总是将数据完整性假定为最坏情况。对数据进行适当的检查和数据校验以保持数据完整性(integrity)。 可能的话,请实现内部校验(checksums )。例如,针对文本文件,应该有一条结尾记录,这个记录将会说明文件中的总记录数和关键字段的集合(aggregate)。 尽可能早地在模拟生产环境下使用真实的数据量,以便于进行计划和执行压力测试。 在大数据量的批量中,数据备份可能会非常复杂和充满挑战,尤其是你的系统要求不间断(24 – 7)运行的系统。数据库备份通常在设计时就考虑好了,但是文件备份也应该提升到同样的重要程度。如果系统依赖于文本文件,文件备份程序不仅要正确设置和形成文档,还要定期进行测试。 https://www.cwiki.us/display/SpringBatchZH/General+Batch+Principles+and+Guidelines
Spring Batch 体系结构
Spring Batch 设计的时候充分考虑了可扩展性和各类终端用户。 下图显示了 Spring Batch 的架构层次示意图,这种架构层次为终端用户开发者提供了很好的扩展性与易用性。 上图显示的是 Spring Batch 层级体系结构 这个层级体系结构高亮显示了 Spring Batch 的 3 个主要组件:应用(Application),核心(Core)和 基础架构(Infrastructure)。 应用层包含了所有的批量作业和开发者使用 Spring Batch 写的所有自定义代码。批量核心层包含了所有运行和控制批量作业所需必要的运行时类。同时还包括了有 JobLauncher, Job, 和 Step 的实现。应用层和核心层都构建在基础架构层之上。 基础架构层包含了有 读(readers)和 写(writers )以及服务(services)。例如有针对服务使用, RetryTemplate。基础架构层的这些东西,这些能够被应用层开发(readers 和 writers,例如  ItemReader 和 ItemWriter)和批量核心框架(例如,retry,这个是核心层自己的库)所使用。 简单的来说,基础架构层为应用层和批量核心层提供了所需要的的基础内容,是整个  Spring Batch 的基础。我们针对 Spring Batch 的开发绝大部分情况是在应用层完成的。   https://www.cwiki.us/display/SpringBatchZH/Spring+Batch+Architecture
Spring Batch 使用场景
一个标准的批处理程序通常会从数据库,文件或者队列中读取大量的数据和记录,然后对获取的数据进行处理,然后将修改后的格式写回到数据库中。 通常 Spring Batch 在离线模式下进行工作,不需要用户干预就能自动进行基本的批处理迭代,进行类似事务方式的处理。批处理是大多数 IT 目的一个组成部分,而 Spring Batch 是唯一能够提供健壮的企业级扩展性的批处理开源框架。 业务场景 周期提交批处理任务 同时批处理进程:并非处理一个任务 分阶段的企业消息驱动处理 高并发批处理 失败后的手动或定时重启 按顺序处理任务依赖(使用工作流驱动的批处理插件) 部分处理:跳过记录(例如,回滚) 全批次事务:因为可能有小数据量的批处理或存在存储过程/脚本中 技术目标 批量的开发者使用 Spring 的编程模式:开发者能够更加专注于业务逻辑,让框架来解决基础的功能 在基础架构、批处理执行环境、批处理应用之间有明确的划分 以接口形式提供通用的核心服务,以便所有项目都能使用 提供简单的默认实现,以实现核心执行接口的“开箱即用” 通过在所有层中对 Spring 框架进行平衡配置,能够实现更加容易的配置,自定义和扩展服务。 所有存在的核心服务应该能够很容易的在不对系统架构层进行影响的情况进行替换或扩展。 提供一个简单的部署模块,使用 Maven 来进行编译的 JARs 架构,并与应用完全分离。   https://www.cwiki.us/display/SpringBatchZH/Usage+Scenarios
Spring Batch 背景
在开源项目及其相关社区把大部分注意力集中在基于 web 和 SOA 基于消息机制的框架中时,基于 Java 的批处理框架却无人问津,尽管在企业 T 环境中一直都有这种批处理的需求。但因为缺乏一个标准的、可重用的批处理框架导致在企业客户的IT系统中存在着很多一次编写,一次使用的版本,以及很多不同的内部解决方案。 SpringSource 和 Accenture(埃森哲)致力于通过合作来改善这种状况。埃森哲在实现批处理架构上有着丰富的产业实践经验,SpringSource 有深入的技术开发积累,背靠Spring框架提供的编程模型,意味着两者能够结合成为默契且强大的合作伙伴,创造出高质量的、市场认可的企业级 Java 解决方案,填补这一重要的行业空白。两家公司目前也正着力于开发基于 Spring 的批处理解决方案,为许多客户解决类似的问题。这同时提供了一些有用的额外的细节和以及真实环境的约束,有助于确保解决方案能够被客户用于解决实际的问题。基于这些原因,SpringSource  和 Accenture 一起合作开发了 Spring Batch。 埃森哲已经贡献了先前自己的批处理体系结构框架,这个框架基于数十年宝贵的经验并基于最新的软件平台(如COBOL/Mainframe, C++/Unix 及现在非常流行的Java平台)来构建 Spring Batch 项目,Spring Batch 未来将会由开源社区提交者来驱动项目的开发,增强,以及未来的路线图。 埃森哲咨询公司与 SpringSource 合作的目标是促进软件处理方法、框架和工具的标准化改进,并在创建批处理应用时能够持续影响企业用户。企业和政府机构希望为他们提供标准的、经验证过的解决方案,而他们的企业系统也将受益于 Spring Batch。 https://www.cwiki.us/display/SpringBatchZH/Background
Spring Batch 介绍
在企业应用的关键环境中,通常有需要很多应用来来处理大量的应用。这商业操作包括了自动化,并且负责的处理程序来对大量数据进行高效的处理,通常这些程序不需要人工进行干预。这些事件包括有基于时间周期产生的操作(例如,月末统计计算,通知或者消息通知,或者定期处理那些业务逻辑非常复杂,并且数据量非常大的操作(例如,保险的保额确定或者保险费率的调整),也有可能是从内部或者外部抓取到的数据的格式化,通常这些数据需要进行格式化,校验,并且通过事务来整合到自己的数据库中。批处理通常被用来针对企业每天产生超过亿万级别的数据量。 Spring Batch是一个轻量级的综合性批处理框架,可用于开发企业信息系统中那些至关重要的数据批量处理业务。Spring Batch 是基于生产率来进行构建的,并且基于 POJO 进行开发,用户也很容易上手使用,让开发者很容易的访问和使用企业级服务。Spring Batch 不是一个自动运行框架。在市面已经有了很多企业级和开源的自动运行框架,例如 Quartz,Tivoli, Control-M 等。Spring Batch 被设计与计划任务和调度程序一同协作完成任务,而没有被设计用来取代任务调度和计划任务。 Spring Batch 提供了可重用的功能,这些功能被用来对大量数据和记录进行处理,包括有日志/跟踪(logging/tracing),事务管理(transaction management),任务处理状态(job processing statistics),任务重启(job restart),任务跳过(job skip)和资源管理(resource management)。 此外还提供了许多高级服务和特性, 使之能够通过优化(optimization ) 和分片技术(partitioning techniques)来高效地执行超大型数据集的批处理任务。 Spring Batch 是一个具有高可扩展性的框架。不管简单还是复杂,还是大批量的处理任务,都可以使用 Spring Batch 框架来实现。   https://www.cwiki.us/display/SpringBatchZH/Spring+Batch+Introduction
Java 如何返回一个指定范围的随机数
希望返回的随机数为整数。 Java 如何返回指定访问内的随机数。 比如说 1 到 100 可以考虑使用下面的代码: int startInclusive = 1; int endExclusive = 100; logger.debug("min <= R <= max - [{}] ", RandomUtils.nextInt(startInclusive, endExclusive));   使用 RandomUtils 类中定义的方法,RandomUtils 定义在下面的 Package 中   org.apache.commons.lang3.RandomUtils Utility library that supplements the standard Random class. Since: 3.3 程序输出为: 2018/12/30 17:01:57 DEBUG [com.ossez.codebank.lang.tests.NumberTest] - min <= R <= max - [42] https://www.cwiki.us/pages/viewpage.action?pageId=41684032
Java 如何生成随机数
请参考页面 随机数 中的内容和 GitHub https://github.com/cwiki-us/codebank-lang/blob/master/src/test/java/com/ossez/codebank/lang/tests/NumberTest.java 中的代码。 主要你可以考虑使用 org.apache.commons.lang3.RandomUtils 和 org.apache.commons.lang.RandomStringUtils 中的 2 个工具类来帮助你实现。 具体的实现方法,请参考工具类中的说明。  
Java 如何生成一个 8 位的字母和数字组合随机字符串
使用下面的方法: RandomStringUtils.randomAlphanumeric(10) 使用的类是: org.apache.commons.lang.RandomStringUtils Operations for random Strings. Currently private high surrogate characters are ignored. These are unicode characters that fall between the values 56192 (db80) and 56319 (dbff) as we don’t know how to handle them. High and low surrogates are correctly dealt with – that is if a high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f) then it is followed by a low surrogate. If a low surrogate is chosen, 56320 (dc00) to 57343 (dfff) then it is placed after a randomly chosen high surrogate. 你可以使用下面的方法: logger.debug("RandomStringUtils - [{}]", RandomStringUtils.randomAlphanumeric(10));   程序输出为: 2018/12/30 17:01:57 DEBUG [com.ossez.codebank.lang.tests.NumberTest] - 9ZhT1dDl49  
Binomial Coefficient(二项式系数)
In mathematics, any of the positive integers that occurs as a coefficient in the binomial theorem is a binomial coefficient. Commonly, a binomial coefficient is indexed by a pair of integers n ≥ k ≥ 0 and is written {\displaystyle {\tbinom {n}{k}}.} {\displaystyle {\tbinom {n}{k}}.} It is the coefficient of the xk term in the polynomial expansion of the binomial power (1 + x)n, and it is given by the formula. 英文描述 英文描述请参考下面的图。 中文描述 根据给定的公式计算二项式的值。 在这里有一个说明需要注意的是,如果结果超过 1,000,000,000 你的程序应该返回 -1。 如果结果没有定义的话,那么你的程序应该也要返回 -1。 思路和点评 在这里的计算,公式比较简单,就是计算 N,K N-K 的阶乘,在阶乘中,你可以使用递归进行计算。 但是需要注意的是对这个数字的阶乘计算量,程序是很容易溢出的,如果从出题者的意图来看就是要考察大数值的计算和计算中的溢出。 如果你使用的是 Java 的话,你应该使用类 BigDecimal,进行计算。如果你可以使用 Apache Common Math 的话,你就直接使用 CombinatoricsUtils.factorialDouble 进行计算。在计算中允许的最大参数值为 170,超过这个值以后就超过程序能够计算的最大值了。 如果你希望直接计算二项式系数的话,你可以使用 CombinatoricsUtils.binomialCoefficientDouble(40, 20) 直接进行计算。 源代码 源代码和有关代码的更新请访问 GitHub: https://github.com/cwiki-us/codebank-algorithm/blob/master/src/test/java/com/ossez/codebank/interview/tests/WayfairTest.java 测试类请参考: https://github.com/cwiki-us/codebank-algorithm/blob/master/src/test/java/com/ossez/codebank/interview/tests/WayfairTest.java 代码思路请参考: /** * https://www.cwiki.us/display/ITCLASSIFICATION/Binomial+Coefficient * * Binomial Coefficient */ @Test public void testBinomialCoefficient() { int n = 40; int k = 20; BigDecimal bc = factorial(n).divide(factorial(k).multiply(factorial(n - k))); // a.compareTo(new BigDecimal(1000000000)) logger.debug("{}", bc); logger.debug("Check for […]


  • No labels