skill set文化产业包含哪些些方面

求写一个段子。_百度知道
求写一个段子。
女主角拉着男二 去和男一看电影的场景 具体就是见了一面就好了
我有更好的答案
按默认排序
咨询和金融的就业空间。牛外企,一样的难进,但金融的空间要大很多。有名的咨询公司就那几个。金融不仅单个公司招人多,牛公司也多:投行类、银行类、甚至可以算上会计类。这部分招人规模也至少高一个数量级。然而最致命的是中间部分招人空间的差距。国内知名的本土咨询企业数来数去就那几家,且其性质决定招人规模不大。然而金融类,有n多的证券公司、基金公司、甚至民营的投资类公司也都不错,单个公司的招人数也比咨询公司要多。这部分规模甚至高两个数量级。从收益上来看,直接的收入和劳动强度相差不大;从发展前景上看,一条是走金融路线,一条是走管理路线,自己权衡,管理类风险显然要大。 比较了咨询和金融的招人需求,也该谈谈人才供给。这两个行业,无论对于高端还是中端,管理类学生都有点优势。不过,管理咨询的门槛比金融类要低,任何一个专业,只要你是最优秀的,都可以尝试管理咨询。金融要高一些,而且不是每个人都对金融感兴趣。需求与供给如此,其竞争程度和结果可以想象了。
总之,我想说,管理咨询――爱你不容易。如果你有足够的实力和准备,会有可观的回报。也许正是这些人才真正是咨询业所需要的吧。”
Clark(新近就职于某国际咨询公司):“不是每个人都适合Consulting的。一个刚从悉尼transfer来的同事说,我们公司在全球都有着相差无几的Staff。A bunch of sharp smart, but everyone is a little weird. 我想说的是,有的时候,并不是你有什么地方不对,而是,你没有找到一个CultureFit的公司。(对所有公司,甚至是四大)特别是Consulting industry,Team实在是很重要,彼此间的Trust常常是和Time在赛跑,因为只要有一个人浪费了他自己的时间,就是整个Team 浪费了时间。
记得那一次,我在整理材料的时候,我的一个Case Manager对我说,如果你不是这样一个Down to Earth的人,我们也没有办法要你。我觉得很奇怪,有很多人想进Consulting,却从来不从自己身上考虑问题:Am I strategic thinking? Am I down to earth? Am I systematic enough to fit the career? 却光想着几年之后可去外国读MBA,几年之后可以赚几万美金。我认识的那些成功的年轻人, 都是超人聪明而有超人扎实的。成功永远不可能信手拈来,也不可能一步登天。”
你现在大概在苦苦思索一个问题:咨询业真正需要的人才究竟是什麽样的呢?
我们再来看看咨询业的资深专家给出了他们自己的看法:
受访人:Jason,咨询业十八年从业经验
做咨询基本上有两种职业选择:要么做专才咨询,要么做通才咨询。专才咨询,顾名思义,就是运用专门的知识来分析现 实机构中的现实问题。这种咨询能为许多机构带来明显的价值,所以是一项了不起的工作。毫无疑问,今天咨询业最热门 的领域是信息技术咨询,正是这些技术增强了许多行业的生产能力。这也是为什么一些大的信息技术咨询公司还将进一步 成长的原因。通才咨询又称管理咨询,主要为企业能够如何更快、更好、更低成本且更高效率地经营提供咨询服务。在美 国,现在有30万人专职从事咨询工作,每年创造超过300亿美元的收入。大约超过一半的咨询人员来自美国,另有四 分之一来自欧洲。目前咨询业发展最快的是发展中国家。   咨询公司通常要求应聘者具备以下素质:   第一,创造新思想的激情。咨询公司生产的并非有形产品,它不能吃、不能穿。它的产品是一个主义、一条建议、一种思 维方式。所以,咨询公司说到底就是一个纯粹的人力资源库。这意味着他们最重要的资产是通过精确思考和认真研究产生的有 用思想。因此,咨询公司喜欢商学院那些最优秀、天资最佳的学生。在咨询业能否做好,智力因素显而易见是十分重要的。一 名优秀的咨询人员必定是一名具有激情的优秀思想者,必须喜欢创造新思想,必须喜欢发现问题、分析问题和解决问题。   当然,学历出身并不能保证一个人的成功。正因如此,MBA学位本身不是必备的。许多公司也聘用有其他学历背景的人。 文凭只是文凭,许多大学本科生也能进入咨询领域。   第二,为客户服务的激情。由于现在咨询公司的薪水很高,许多人是为了挣钱而进入咨询公司,不是为了咨询工作进入这 个领域。不管怎么说,咨询毕竟是一个服务行业,作为一名顾问,你必须尽力满足客户的要求。你将总是为帮助别人而工作。 你服务客户的能力将决定你事业的成功以及你所在公司的前途。一位资历颇深的前麦肯锡咨询人员这样写道:“只有个人获得 了成就感,这项职业才会变得真正有趣。那些展现出优秀才能的人,在他们职业生涯的早期就获得了一定的个人控制权。他们 要求在任何时候都拥有多种选择的机会,他们通常很快就成为部门经理,并为他们的小组确定工作进程。通过工作中展现的协 调和领导才能,他们赢得了客户、上司及组员的尊敬。一些不太友善的客户在听富有成就的咨询顾问谈话时渐渐变得虚心认真, 原因是那些咨询人员做出了非凡的成绩。那些表现卓越的人往往对自己十分满意,而且更能把咨询方面的经验当做一条通往成 功的道路。对他们来说,金钱回报只是把咨询作为第一选择的次要原因,而真正的原因在于追求职业生涯的最高成就。” 第三,对人的激情。一位咨询员曾经告诉我,他生活中一些关系最好的朋友正是他的客户。这并不说明他不珍惜妻子和家 庭,而是因为通过多次合作加上自己的工作成绩,他和许多客户建立了终身持久的合作关系。有了这种关系,他感到,即 使在工作中多花一些时间,遭遇某些挫折,也是值得的。一般而言,喜欢与人交谈的人更容易成为一名优秀的咨询人员, 因为爱社交的人会与他们的组员和客户相处得很好。这就是说你必须是一个外向型的人,你必须喜欢、理解你的客户,必 须让人乐于和你交往,不管你是靠魅力、幽默、善于倾听,还是靠努力工作做到这一点。 你现在应该大概明白了,咨询公司对人的要求是多方面的: 聪明、讨人喜欢、乐于助人的人是咨询公司想要的。当然,不同公司聘人的过程可能差别很大。许多公司在寻找真正具有 独特能力的人。其他的条件包括需要了解一些具体的商业问题,能容忍超长时间的加班,掌握娴熟的信息技术,具备较佳 的个人形象,具有迅速处理大量资料的能力以及较强的逻辑思维能力、写作能力和语言表达能力,并且愿意经常出差。 事实上,咨询业有一套特定的素质集合——咨询素质集合(Consulting Skill Set)——作为一名咨询顾问应 具备的基本素质。试着回答下面的问题,我们一起来测试你的素质集合里是否包含适合咨询行业的特点呢? ⑴你是否喜欢团队合作? A.T. Kearney的人喜欢说一句话:“Consultants work alone together”。这句话并不说他们单独工作,相反,咨询 顾问们总是进行团队工作。他们不只会经常与团队里的其他成员进行“头脑风暴”,他们还经常与客户公司的 员工一起工作,甚至与客户公司雇用的其他咨询公司的人一起工作。他们还经常开会,采访各种可能的信息
来源。如果你是比较喜欢独自在安静的环境中工作的人,那你是无法从咨询工作中享受到乐趣的。记住,在 咨询行业中存在着一句至理名言:Trying to do it all yourself doesn’t always make you look like a hero!
Leadership 和Teamwork是否有冲突?
“听霸”们会发现,很多(准确地说是大多数)咨询公司在宣讲会上都会强调他们looking for的人需要有strong leadership & good teamwork——特别是我们上面提到的good teamwork。于是很多人都会发出这样的疑问:有很 强的领导力是不是意味着aggresive?那和团队协作能力是否有矛盾?
我们专门就这个问题采访了很多咨询内部的人,经过他们的耐心解释,我们终于明白了咨询公司所要求的 Leadership和Teamwork之间的关系了,这二者一点都不矛盾:“在咨询公司,我们的工作方式是项目式,需要 和团队里的其他成员进行合作,所以团队协作能力是必须的;每个人都需要一定的领导才能,这里指的领导 才能与agrresive并不等同,而是指我们要懂得如何管理各种资源:管理我们的合作伙伴,管理我们的上级,管 理我们的客户等等。在我们咨询中流传的一句话:Work alone together指的就是需要同时兼备领导力与团队协作 能力。”
这样的解释是否让你搞明白了呢?
⑵你是否能在压力下从事多项工作?咨询顾问的项目工作非常繁重,而且他们还有可能会同时参与多个项目,这就需要你能够承受压力,还要求你
具有不错的组织协调能力?另外,工作之外你的个人生活是否能保持有序?这些都是你需要问一问自己的问题。
⑶你是否喜欢与人交谈?你觉得整个午餐或晚餐都进行谈话是否有意思?如果你认为自己性格内向,觉得整天与人交谈会使你筋疲力尽 的话,很可能你会觉得咨询很无聊。相反,如果你很喜欢开会,与专家交流,表达你的观点,说服别人与你合
作并且很热衷于做即兴的演讲,那么你就具备咨询素质集合中非常重要的一个要求了。 ⑷你是否喜欢学校?你是不是真的喜欢上课和完成研究作业?这一点之所以重要是因为,是否有学术上好奇心与是否喜欢咨询行业之间是有很大的相关度的。
⑸你是否对数字敏感?咨询公司并不期望你是一个数学教授,但是你必须接受数字和需要经常使用的程序,如Exel, Access和PowerPoint。如果你讨厌数学,那你将会讨厌咨询。与此相关的,你同样必须喜欢并且擅长分析及创造性的思维:咨询行业中有一个术语,跳出盒子的思考(Out of the box thinking),指的是用非常规的方法解决问题的能力。
国贸附近出租车司机说,凌晨2点钟下班的是做广告媒体的,4点钟是四大的,不下班的是咨询的……
⑹你是否愿意每周工作70—80个小时?咨询顾问的职责是满足客户的预期,所以如果你必须一周工作80个小时才能达到客户要求的话,那你也只能认命了。你可以试试每天从上午9点工作到晚上12点,从周一到周五,坚持一个月后,你就能理解80小时/周的工作对你来说意味着什么,你也能判断出自己是否能够胜任咨询行业的工作了。
⑺你是否愿意经常出差?千万不要轻率地作出肯定回答——事实上频繁旅行经常成为很多人退出咨询行业的原因。下面我们将就旅行是否会成为一个Problem进行专门的讨论: 旅行是问题吗?
正如我们在前面所讲到的那样,进入咨询行业中后将面临大量的“旅行”。喜欢旅游的你此时是不是心中暗喜:“旅行呀?我喜欢”,“一周四天旅行?没问题!”先停止幻想在夏威夷的沙滩上晒太阳吧! 还是先回答下面的问题,再给出你最后的答案吧!
※你是否讨厌外出准备行李?外出时你是否总是带的行李不够或者过多?
※你讨厌坐飞机吗?讨厌开车吗? ※你介意长时间住在旅馆里吗?当你想到要去遥远的城市并每周在那里过三到四个晚上,连续十周,你感觉舒服吗? ※如果你结婚了,你介意每周有三个晚上要离开你的老公(or老婆)和孩子(如果你有的话)吗?他们介意吗? ※如果你因为客户要求你多留一天而不得不取消某个重要的约会时,你的他/她能否理解? 如果上述问题让你感到不舒服的话,那么你就要慎重考虑一下是否选择咨询行业了。当然如果你非常喜爱咨询这个行业,也可以找到一个折衷的方法,就是寻找那些承诺更加稳定的工作环境的咨询公司,或者留意一下内部的咨询机构吧。 最后提醒你也不必过于担心,旅行在咨询业确实非常常见。当然并不是所有咨询顾问都要旅行,并且不是所有客户都会要求你总在他那里,这取决于该公司的旅行模式、行业、你的位置、以及最重要的——你的项目。
总的来说,对咨询业抱有积极看法并能坚持做下去而不放弃的人,多是那些在繁重工作压力下仍能不断进步的人;他们能同时处理多项工作,并能成功应付不确定的情形;在经受压力和疲劳时他们仍能保持冷静的头脑并能集中精力工作;另外,他们也是具有创新精神的人。
当然,我们一直牢牢记住本章的目的是帮助你确定咨询行业是否合适你,或者说你与咨询是否match,所以关于进入咨询行业后需要面对的更多的情况及所需要掌握的技巧在本章中不做赘述,而是将此重任交给本书的第三部分“咨询生涯”——你可以在那里找到更多咨询生涯的信息。 咨询看什么? From BCG 咨询公司在挑选简历时看重的素质有:优异的学习成绩,出众的实习背景,交流学生的国际经验,丰富的社会活动(体现良好的人际沟通能力),简历的格式和文风(很多人的简历十分粗糙,其实内容十分吸引人,但却没有能够在5秒钟内吸引各公司HR的排版技术和形式),良好的英语技巧(有些公司看重TOEFL,GRE,四六级成绩)。除此之外,Boston有一些自己的标准。如外语要非常好,因为我们的manager很多都是foreigner,我们平时用英文沟通,报告也都是用英文撰写。Boston喜欢成绩好的人,所以同等条件下,成绩越好、奖学金越多、英语越好的人,Boston越喜欢。总的来说,Boston特别喜欢聪明的人。 From Booz Allen Hamilton 作为局外人,我们的身价很高。如果只做公司职员自己能解决的事情,或未经仔细考虑就机械地对一些管理理念表示赞同,我们就没有体现出应有的价值。拥有了坚定的理念之后我们才能阐明自己的看法。咨询顾问要清楚自己在讲什么。我们必须运用经验有效而迅速地解决客户问题。工作原则和纲要应能提供一套有效的评估标准,它适用于每个新情况并能迅速对其作出反映。此外,我们已确定了前进和进行实践的最好方法。 From Bain 实际上国际知名的咨询公司在校园招聘中看重的是刚从校园毕业的头脑灵活、充满活力的年轻人所具有的巨大潜力,因而针对他们而设置的起步职位并不偏重所学专业,而更注重应聘者的综合素质,这其中包括英语水平、反应速度、基本的商业常识储备、敏锐的商业感知、出色的沟通能力、卓越的领导能力、困难面前的沉着冷静等。在对众多申请者进行简单而又严格的筛选后,有幸进入后续环节的应聘者将会接受咨询行业传统面试项目case interview,即模拟真实商业情境的案例面试。在30至45分钟一对一的讨论中,一个应聘者是否与咨询行业的素质要求以及公司的文化氛围相互匹配,面试官绝对已经了然于胸了。
在上面提到的这些素质要求中,有少数是可以通过有意识的训练而快速掌握的,比如应对案例面试的思路以及方法体系,这些甚至在咨询公司的网站上都为大家提供详尽的指导;而大多数素质不可能在短时间速成,它们几乎都是融入性格的成分,这有也恰恰是为什么公司的网站上没有这些方面的简要指导。因为公司要寻找的,正是那些在根本素质上“match”的年轻人。
From A.T. Kearney 咨询行业具有如下的特点:工作强度大、工作压力大、项目制工作方式、需要不断与客户沟通等等,这些特点决定了咨询行业的从业人员首先不仅要愿意接受挑战,而且要喜欢挑战,否则很难长时间坚持下来;此外要有很强的逻辑思维能力、接受能力(学习能力)、沟通能力、领导力与团队协作能力是否可以解决您的问题?
其他类似问题
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
XX智慧资本战略
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口[Jakarta Commons笔记] 开篇
st1":*{behavior:url(#ieooui) }
在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默默无闻的。在我看来,成功而默默无闻的那些框架值得我们格外的尊敬和关注,Jakarta
Commons就是这样的一个框架。如果你至少参与了一个中型规模的Java项目,那么我想有超过一大半的机会你都接触和使用到了Jakarta
Commons,不管你自己有没有察觉。就我所知,除了Apache
Jakarta其他许多开源框架之外,不少所谓的商业框架其实内部有些模块是借用Commons的,甚至有一些完全就是对Commons的类进行了简单的封装。如果真的没有接触过也不要紧,当你看到它时,你自然会被它的简单而强大所吸引。
要提高Java编程水平,一条可以走的路就是学习优秀的开源框架。这又要分两个层面:应用层面和源码层面。从应用来说,开源的框架大都可以给你带来生产力和/或代码质量的大幅提升;从源码来说,Java开源框架,尤其是那些大型的优秀的框架,其源码对广大Java爱好者来说都是一笔巨大的财富,你可以从中学到许多课本上学不到的东西:编码习惯、代码组织、注释、文档、如何用Java解决实际问题、特定问题的算法,等等。而这些对于我们的作为软件开发者的实际工作而言,相当有意义。
熟悉Jakarta
Commons的朋友可能会觉得现在是不是有点过时,因为有很多功能在J2SE
5.0中已经包含了。其实这个问题看你怎么去看,一方面,J2SE
5.0毕竟是刚出现不久的Java版本,实际应用中,很多时候我们需要把代码兼容等级维持在1.3或者1.4,所以很多5.0的功能我们暂时还不能放开手脚去使用;另一方面,鉴于Jakarta在一定程度上反映了一线Java开发人员的实际需求,而目前5.0已经采纳了其中许多特性,我们当然也有理由相信未来的Java版本还会继续参照Jakarta
Commons的内容。有这么一套开发源码、免费使用、商业友好的优秀API作为Java自带API的补充,何乐而不为呢?
我打算在近期陆续做一些Jakarta
Commons的学习笔记放上来,供大家参考。
有关Jakarta的最新动态和详细信息,可以参考:
跟java.lang这个包的作用类似,Commons
Lang这一组API也是提供一些基础的、通用的操作和处理,如自动生成toString()的结果、自动实现hashCode()和equals()方法、数组操作、枚举、日期和时间的处理等等。目前这组API的版本是2.1,下载地址如下:
其中后一个是源代码。
这一组API的所有包名都以mons.lang开头,共有如下8个包:
其中的lang.enum已不建议使用,替代它的是紧随其后的lang.enums包。
lang包主要是一些可以高度重用的Util类;lang.builder包包含了一组用于产生每个Java类中都常使用到的toString()、hashCode()、equals()、compareTo()等等方法的构造器;lang.enums包顾名思义用于处理枚举;lang.exception包用于处理Java标准API中的exception,为1.4之前版本提供Nested
Exception功能;lang.math包用于处理数字;lang.mutable用于包装值型变量;lang.time包提供处理日期和时间的功能。
由于Commons的包和类实在很多,不可能一个一个讲了,在接下来的专题文章中我就只分别过一下lang、lang.builder、lang.math和lang.time这几个包和常见的用法,其他的我们可以在用到时临时参考一下Javadoc。位置就在安装路径的
…"commons-lang-2.1"docs"api"index.html
我们首先来看mons.lang包,这个包提供了一些有用的包含static方法的Util类。除了6个Exception类和2个已经deprecated的数字类之外,commons.lang包共包含了17个实用的类:
接下来我准备用两个例子来分别说明ArrayUtils和StringUtils的常见用法。
数组是我们经常需要使用到的一种数据结构,但是由于Java本身并没有提供很好的API支持,使得很多操作实际上做起来相当繁琐,以至于我们实际编码中甚至会不惜牺牲性能去使用Collections
API,用Collection当然能够很方便的解决我们的问题,但是我们一定要以性能为代价吗?ArrayUtils帮我们解决了处理类似情况的大部分问题。来看一个例子:
sean.mons.
java.util.M
mons.lang.ArrayU
ArrayUtilsUsage {
main(String[] args) {
// data setup
[] intArray1 = { 2, 4, 8, 16
[][] intArray2 = { { 1, 2 }, { 2, 4
}, { 3, 8 }, { 4, 16 } };
Object[][] notAMap = {
&&&&&&&&&&&&&&&
Double(100) },
&&&&&&&&&&&&&&&
Double(80) },
&&&&&&&&&&&&&&&
Double(60) },
&&&&&&&&&&&&&&&
Double(40) },
&&&&&&&&&&&&&&&
Double(20) }
// printing arrays
System.out.println("intArray1: " +
ArrayUtils.toString(intArray1));
System.out.println("intArray2: " +
ArrayUtils.toString(intArray2));
System.out.println("notAMap: " +
ArrayUtils.toString(notAMap));
// finding items
System.out.println("intArray1 contains '8'?
&&&&&&&&&&&&&&&
+ ArrayUtils.contains(intArray1, 8));
System.out.println("intArray1 index of '8'?
&&&&&&&&&&&&&&&
+ ArrayUtils.indexOf(intArray1, 8));
System.out.println("intArray1 last index of '8'?
&&&&&&&&&&&&&&&
+ ArrayUtils.lastIndexOf(intArray1, 8));
// cloning and resversing
int[] intArray3 = ArrayUtils.clone(intArray1);
System.out.println("intArray3: " +
ArrayUtils.toString(intArray3));
ArrayUtils.reverse(intArray3);
System.out.println("intArray3 reversed:
&&&&&&&&&&&&&&&
+ ArrayUtils.toString(intArray3));
// primitive to Object array
Integer[] integerArray1 = ArrayUtils.toObject(intArray1);
System.out.println("integerArray1:
&&&&&&&&&&&&&&&
+ ArrayUtils.toString(integerArray1));
// build Map from two dimensional array
Map map = ArrayUtils.toMap(notAMap);
Double res = (Double) map.get("C");
System.out.println("get 'C' from map: " +
以下是运行结果:
这段代码说明了我们可以如何方便的利用ArrayUtils类帮我们完成数组的打印、查找、克隆、倒序、以及值型/对象数组之间的转换等操作。如果想了解更多,请参考Javadoc。
处理文本对Java应用来说应该算是家常便饭了,在1.4出现之前,Java自身提供的API非常有限,如String、StringTokenizer、StringBuffer,操作也比较单一。无非就是查找substring、分解、合并等等。到1.4的出现可以说Java的文字处理上了一个台阶,因为它支持regular
expression了。这可是个重量级而方便的东东啊,缺点是太复杂,学习起来有一定难度。相较而言,Jakarta
Commons提供的StringUtils和WordUtils至今还维持着那种简洁而强大的美,使用起来也很顺手。来看一个例子:
sean.mons.
mons.lang.StringU
StringUtilsAndWordUtilsUsage
main(String[] args) {
// data setup
String str1 = "";
String str2 = " ";
String str3 = ""t";
String str4 = ;
String str5 = "123";
String str6 = "ABCDEFG";
String str7 = "It feels good to use Jakarta
Commons."r"n";
// check for empty strings
System.out.println("==============================");
System.out.println("Is str1 blank? " +
StringUtils.isBlank(str1));
System.out.println("Is str2 blank? " +
StringUtils.isBlank(str2));
System.out.println("Is str3 blank? " +
StringUtils.isBlank(str3));
System.out.println("Is str4 blank? " +
StringUtils.isBlank(str4));
// check for numerics
System.out.println("==============================");
System.out.println("Is str5 numeric? " +
StringUtils.isNumeric(str5));
System.out.println("Is str6 numeric? " +
StringUtils.isNumeric(str6));
// reverse strings / whole words
System.out.println("==============================");
System.out.println("str6: " +
System.out.println("str6 reversed: " +
StringUtils.reverse(str6));
System.out.println("str7: " +
String str8 = StringUtils.chomp(str7);
str8 = StringUtils.reverseDelimited(str8, '
System.out.println("str7 reversed whole words :
"r"n" + str8);
// build header (useful to print log messages that are easy to
System.out.println("==============================");
System.out.println("print
header:");
String padding = StringUtils.repeat("=",
String msg = StringUtils.center(" Customised Header
", 50, "%");
Object[] raw =
Object[]{padding,
msg, padding};
String header = StringUtils.join(raw, ""r"n");
System.out.println(header);
输出的结果如下:
从代码中我们可以大致了解到这个StringUtils类简单而强大的处理能力,从检查空串(对null的情况处理很得体),到分割子串,到生成格式化的字符串,使用都很简洁,也很直截了当。
在前面的专题文章中,我们一起过了一遍mons.lang包,接下来我们继续看mons.lang.builder这个包。在这里面我们可以找到7个类,用于帮助我们实现Java对象的一些基础的共有方法。这7个类分别是:
我们知道,在实际应用中,其实经常需要在运行过程中判定对象的知否相等、比较、取hash、和获取对象基本信息(一般是产生log日志)。然而实现这些compareTo、equals、hashCode、toString其实并非那么直截了当,甚至稍有不注意就可能造成难以追踪的bug,而且这些方法手工维护的话,比较繁琐,也容易出错。于是Commons
Lang在builder这个包中提供了上述辅助类,为我们简化这些方法的实现和维护。
来看一个例子:
sean.mons.
java.util.D
mons.pareToB
mons.lang.builder.EqualsB
mons.lang.builder.HashCodeB
mons.lang.builder.ToStringB
mons.lang.builder.ToStringS
BuilderUsage {
main(String[] args) {
Staff staff1 =
Staff(123, "John Smith", new Date());
Staff staff2 =
Staff(456, "Jane Smith", new Date());
System.out.println("staff1's info: " +
System.out.println("staff2's info: " +
System.out.println("staff1's hash code: " +
staff1.hashCode());
System.out.println("staff2's hash code: " +
staff2.hashCode());
System.out.println("staff1 equals staff2? " +
staff1.equals(staff2));
Comparable
String staffN
Date dateJ
Staff( staffId, String staffName, Date dateJoined)
this.staffId = staffId;
this.staffName = staffN
this.dateJoined = dateJ
compareTo(Object o) {
Staff.class.isAssignableFrom(o.getClass())) {
&&&&&&&&&&&
Staff s = (Staff)
&&&&&&&&&&&
CompareToBuilder()
&&&&&&&&&&&&&&&&&&&
.append(dateJoined, s.getDateJoined())
&&&&&&&&&&&&&&&&&&&
.append(staffName, s.getStaffName()).toComparison();
equals(Object o) {
Staff.class.isAssignableFrom(o.getClass())) {
&&&&&&&&&&&
Staff s = (Staff)
&&&&&&&&&&&
EqualsBuilder()
&&&&&&&&&&&&&&&&&&&
.append(staffId, s.getStaffId())
&&&&&&&&&&&&&&&&&&&
.isEquals();
hashCode() {
HashCodeBuilder(11,
23).append(staffId).toHashCode();
String toString() {
ToStringBuilder(, ToStringStyle.MULTI_LINE_STYLE)
&&&&&&&&&&&&&&&
.append("staffId", staffId)
&&&&&&&&&&&&&&&
.append("staffName", staffName)
&&&&&&&&&&&&&&&
.append("dateJoined", dateJoined)
&&&&&&&&&&&&&&&
.toString();
Date getDateJoined()
setDateJoined(Date dateJoined) {
.dateJoined =
getStaffId() {
setStaffId(long staffId) {
.staffId = staffId;
String getStaffName()
setStaffName(String staffName) {
.staffName = staffN
以下是运行结果:
这些builder使用起来都很简单,new一个实例,append需要参与的信息,最后加上toComparison、isEquals、toHashCode、toString这样的结尾即可。相应的,如果你不需要这样级别的控制,也可以使用利用反射机制的版本自动化实现需要的功能,如:
compareTo(Object o) {
CompareToBuilder.reflectionCompare(,
equals(Object o) {
EqualsBuilder.reflectionEquals(,
hashCode() {
HashCodeBuilder.reflectionHashCode();
String toString() {
ReflectionToStringBuilder.toString();
尤其当我们在项目中不希望过多的参与到对这些对象方法的维护时,采用Commons提供的利用反射的这些API就成了方便而相对安全的一个方案。
Commons中,专门处理数学计算的类分别可以在两个地方找到:一是Commons
Lang的mons.lang.math包中,二是在Commons
Math这个单独的子项目中。由于后者主要是处理复数、矩阵等,相对使用比较少,在我的笔记中就只简单讲讲Commons
Lang中的math包。对后者感兴趣的可以看看
mons.lang.math包中共有10个类,这些类可以归纳成四组:
下面我举个例子分别说明上述四组的使用方法:
sean.mons.
mons.lang.ArrayU
mons.lang.BooleanU
mons.lang.StringU
mons.lang.math.DoubleR
mons.lang.math.F
mons.lang.math.NumberU
mons.lang.math.RandomU
mons.lang.math.R
LangMathUsage {
main(String[] args) {
demoFraction();
demoNumberUtils();
demoNumberRange();
demoRandomUtils();
demoFraction() {
System.out.println(StringUtils.center(" demoFraction
", 30, "="));
Fraction myFraction = Fraction.getFraction(144, 90);
// Fraction myFraction = Fraction.getFraction("1
System.out.println("144/90 as fraction: " +
myFraction);
System.out.println("144/90 to proper: " +
myFraction.toProperString());
System.out.println("144/90 as double: " +
myFraction.doubleValue());
System.out.println("144/90 reduced: " +
myFraction.reduce());
System.out.println("144/90 reduced proper:
&&&&&&&&&&&&&&&
+ myFraction.reduce().toProperString());
System.out.println();
demoNumberUtils() {
System.out.println(StringUtils.center("
demoNumberUtils ", 30, "="));
System.out.println("Is 0x3F a number?
&&&&&&&&&&&&&&&
+ StringUtils.capitalize(BooleanUtils.toStringYesNo(NumberUtils
&&&&&&&&&&&&&&&&&&&&&&&
.isNumber("0x3F"))) + ".");
[] array = { 1.0, 3.4, 0.8, 7.1,
NumberUtils.max(array);
NumberUtils.min(array);
String arrayStr = ArrayUtils.toString(array);
System.out.println("Max of " + arrayStr + " is: " + max);
System.out.println("Min of " + arrayStr + " is: " + min);
System.out.println();
demoNumberRange() {
System.out.println(StringUtils.center("
demoNumberRange ", 30, "="));
Range normalScoreRange = new DoubleRange(90, 120);
score1 = 102.5;
score2 = 79.9;
System.out.println("Normal score range is: " +
normalScoreRange);
System.out.println("Is "
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
+ " a normal score? "
&&&&&&&&&&&&&&&
+ StringUtils
&&&&&&&&&&&&&&&&&&&&&&&
.capitalize(BooleanUtils.toStringYesNo(normalScoreRange
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
.containsDouble(score1))) + ".");
System.out.println("Is "
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
+ " a normal score? "
&&&&&&&&&&&&&&&
+ StringUtils
&&&&&&&&&&&&&&&&&&&&&&&
.capitalize(BooleanUtils.toStringYesNo(normalScoreRange
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
.containsDouble(score2))) + ".");
System.out.println();
demoRandomUtils() {
System.out.println(StringUtils.center("
demoRandomUtils ", 30,
for (int i = 0; i & 5; i++) {
&&&&&&&&&&&
System.out.println(RandomUtils.nextInt(100));
System.out.println();
以下是运行结果:
以上就是Commons
Lang的math包通常的用法。提一下NumberUtils.inNumber(String)方法,它会正确判断出给定的字符串是否是合法的数值,而我在前面的笔记中提到的StringUtils.isNumeric(String)只能判断一个字符串是否是由纯数字字符组成。Commons
Lang的math包的各个类都还有很多实用的方法,远不止我在例子中用到的这些,如果你感兴趣,参照一下Commons
Lang的Javadoc吧。
好了,来看我在Common
Lang中最后要讲的一个包:mons.lang.time。这个包里面包含了如下5个类:
我们还是在一个例子中来看上述各个类的用法吧:
sean.mons.
java.util.C
java.util.D
mons.lang.StringU
mons.lang.time.DateFormatU
mons.lang.time.DateU
mons.lang.time.FastDateF
mons.lang.time.StopW
DateTimeUsage {
main(String[] args) {
demoDateUtils();
demoStopWatch();
demoDateUtils() {
System.out.println(StringUtils.center(" demoDateUtils
", 30, "="));
Date date =
String isoDateTime =
DateFormatUtils.ISO_DATETIME_FORMAT.format(date);
String isoTime = DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(date);
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM");
String customDateTime = fdf.format(date);
System.out.println("ISO_DATETIME_FORMAT: " +
isoDateTime);
System.out.println("ISO_TIME_NO_T_FORMAT: " +
System.out.println("Custom FastDateFormat: " +
customDateTime);
System.out.println("Default format: " +
System.out.println("Round HOUR: " +
DateUtils.round(date, Calendar.HOUR));
System.out.println("Truncate HOUR: " +
DateUtils.truncate(date, Calendar.HOUR));
System.out.println();
demoStopWatch() {
System.out.println(StringUtils.center(" demoStopWatch
", 30, "="));
StopWatch sw = new StopWatch();
sw.start();
operationA();
sw.stop();
System.out.println("operationA used " +
sw.getTime() + " milliseconds.");
System.out.println();
operationA() {
&&&&&&&&&&&
Thread.sleep(999);
(InterruptedException e)
&&&&&&&&&&&
// do nothing
以下是运行结果:
具体的调用细节和完整的API请参阅Commons
Lang的Javadoc。
Commons项目提供了相当丰富的API,我们之前了解到的Commons
Lang只是众多API的比较核心的一小部分而已。Commons下面还有相当数量的子项目,用于解决各种各样不同方向的实际问题,BeanUtils就是其中的一个,用于处理JavaBeans。它利用Java的反射机制,从动态的生成对bean的getter和setter的调用代码,到模拟创建一个动态的bean,等等。这个包看似简单,却是很多开源项目的基石:如在著名的Struts和Spring
Framework中,我们都能找到BeanUtils的影子。大家猜猜看,有哪位名人是BeanUtils的作者之一?没错,就是Struts的创始人Craig
McClanahan。
BeanUtils最核心的好处在于:我们在编码时,并不需要知道我们处理的JavaBeans具体是什么类型,有哪些属性,这些信息是可以动态获取的,甚至我们都可以不必去关心事实上是否存在这样一个具体的JavaBean类。我们只需要知道有一个JavaBean的实例,我们需要从中取得某个属性,设定某个属性的值,或者仅仅是需要一个属性表。要做到这些,依靠Sun提供的JavaBean规范似乎找不到一个很直接的方式,除非硬编码,将getXxxx()和setXxxx()直接写进我们的程序。但是这样就大大增加了代码的复杂度、耦合性和维护成本。还好Commons
BeanUtils对这个问题提供了一种优雅的解决方案。
我们有两种途径获取Commons
BeanUtils的binary:
从Struts、Spring或者任何依赖BeanUtils的开源产品的发行包中找到相应的jar文件;
BeanUtils的源码下载地址:
BeanUtils一共包括如下5个包:
其中需要我们特别关注的是这个mons.beanutils包,其他包都是起辅助作用的。接下来我们就仔细看一看这个包都有些什么东东:
该接口定义了如下方法:
只要实现了这个Converter接口并注册到ConvertUtils类即可被我们的BeanUtils包所使用,它的主要目的是提供将给定的Object实例转换为目标类型的算法。我们可以在beanutils.converters包中找到相当多的已经实现的转换器。
该接口定义的是一个动态的JavaBean,它的属性类型、名称和值都是可以动态改变的。
该接口定义的是针对实现了DynaBean接口的类的java.lang.Class对象,提供如getName()、newInstance()等方法。
MutableDynaClass
该接口是对DynaClass的扩展,使得动态bean的属性可以动态增加或删除。
BasicDynaBean
DynaBean接口的最精简实现
BasicDynaClass
DynaClass接口的最精简实现
提供通过反射机制填写JavaBeans属性的工具/静态方法
BeanUtilsBean
BeanUtils类的实例化实现,区别于BeanUtils的静态方法方式,使得自定义的配置得以保持
ConstructorUtils
同MethodUtils类似,不过专注于构造方法
ContextClassLoaderLocal
针对每个classloader的唯一标识
ConvertingWrapDynaBean
包含了标准JavaBean实例的DynaBean实现,使得我们可以使用DynaBean的API来访问起属性,同时提供设定属性时的类型转换,继承自并区别于WrapDynaBean
ConvertUtils
提供工具/静态方法,用于将String对象及其数组转换为指定的类型的对象及其数组。
ConvertUtilsBean
ConvertUtils类的实例化实现,区别于ConvertUtils的静态方法方式,使得自定义的配置得以保持
DynaProperty
用于描述DynaBean的属性
JDBCDynaClass
为DynaClass的JDBC实现提供公用的逻辑
LazyDynaBean
懒载入DynaBean,自动往DynaClass添加属性并提供懒载入List和懒载入Map的功能
LazyDynaClass
实现MutableDynaClass接口的类
LazyDynaMap
为Map实例提供一个轻量级的DynaBean包装
MappedPropertyDescriptor
用于描述映射的属性
MethodUtils
包含了针对一般意义上的方法而非特定属性的反射工具/静态方法
MethodUtils.MethodDescriptor
描述通过反射查找某个方法所使用的键值
PropertyUtils
提供利用Java反射API调用具体对象的getter和setter的工具/静态方法
PropertyUtilsBean
PropertyUtils类的实例化实现,区别于PropertyUtils的静态方法方式,使得自定义的配置得以保持
ResultSetDynaClass
包装java.sql.ResultSet中的java.sql.Row实例的DynaBean所对应的DynaClass实现
ResultSetIterator
针对ResultSetDynaClass的java.util.Iterator实现
RowSetDynaClass
DynaClass的一种实现,用于在内存中创建一组表示SQL查询结果的DynaBeans,区别于ResultSetDynaClass,它不需要保持ResultSet打开
WrapDynaBean
DynaBean的一种实现,包含一个标准的JavaBean实例,以便我们可以使用DynaBean的API去访问它的属性,区别于ConvertingWrapDynaBean,它不做专门的类型转换
WrapDynaClass
DynaClass的一种实现,针对那些包装标准JavaBean实例的DynaBeans
[3个Exception]
看到这么多东西是不是有点头晕?不要慌,看几个例子就明白了。只要把握好BeanUtils本身要完成的事,就不难理解这些类存在的道理。我们不妨把BeanUtils的基础应用分解成:访问JavaBean的属性、设定JavaBean的属性、以及创建和使用DynaBeans。这样来看BeanUtils,你就会觉得简单清晰得多。
例子将在下一节单独放出。
假定我们有如下两个标准的JavaBean:
Address.java */
String zipC
Address() {
Address(String zipCode, String
addr, String city, String country) {
.zipCode = zipC
.country =
String getAddr() {
setAddr(String addr) {
String getCity() {
setCity(String city) {
String getCountry() {
setCountry(String country) {
.country =
String getZipCode() {
setZipCode(String zipCode) {
.zipCode = zipC
Customer.java */
Customer {
Customer() {
Customer( id, String name, Address[] addresses)
.addresses =
Address[] getAddresses()
setAddresses(Address[] addresses)
.addresses =
setId( id) {
String getName() {
setName(String name) {
我们来看看通常我们是怎样利用Commons
BeanUtils来完成一些基本的JavaBean和DynaBean操作:
mons.beanutils.BasicDynaB
mons.beanutils.BasicDynaC
mons.beanutils.DynaB
mons.beanutils.DynaP
mons.beanutils.PropertyU
mons.lang.StringU
BeanUtilsUsage {
main(String[] args)
Exception {
demoNormalJavaBeans();
demoDynaBeans();
demoNormalJavaBeans()
Exception {
System.out.println(StringUtils.center("
demoNormalJavaBeans ", 40,
// data setup
Address addr1 =
Address("CA1234", "xxx",
"Los Angeles",
Address addr2 =
Address("100000", "xxx",
"Beijing", "China");
Address[] addrs =
Address[2];
addrs[0] = addr1;
addrs[1] = addr2;
Customer cust =
Customer(123, "John Smith", addrs);
// accessing the city of first address
String cityPattern = "addresses[0].city";
String name = (String) PropertyUtils.getSimpleProperty(cust, "name");
String city = (String) PropertyUtils.getProperty(cust, cityPattern);
Object[] rawOutput1 =
Object[] {
"The city of customer ", name,
&&&&&&&&&&&&&&&
"'s first address is ", city, "." };
System.out.println(StringUtils.join(rawOutput1));
// setting the zipcode of customer's second address
String zipPattern = "addresses[1].zipCode";
(PropertyUtils.isWriteable(cust,
zipPattern)) {
&&&&&&&&&&&
System.out.println("Setting zipcode
&&&&&&&&&&&
PropertyUtils.setProperty(cust, zipPattern, "200000");
String zip = (String) PropertyUtils.getProperty(cust, zipPattern);
&&& Object[] rawOutput2 =
Object[] {
"The zipcode of customer ", name,
&&&&&&&&&&&&&&&
"'s second address is now ", zip, "." };
System.out.println(StringUtils.join(rawOutput2));
System.out.println();
demoDynaBeans()
Exception {
System.out.println(StringUtils.center(" demoDynaBeans
", 40, "="));
// creating a DynaBean
DynaProperty[] dynaBeanProperties =
DynaProperty[] {
&&&&&&&&&&&&&&&
DynaProperty("name", String.class),
&&&&&&&&&&&&&&&
DynaProperty("inPrice", Double.class),&
&&&&&&&&&&&&&&&
DynaProperty("outPrice", Double.class),
BasicDynaClass cargoClass =
BasicDynaClass("Cargo", BasicDynaBean.class,
dynaBeanProperties);
DynaBean cargo = cargoClass.newInstance();
// accessing a DynaBean
cargo.set("name", "Instant Noodles");
cargo.set("inPrice", new
Double(21.3));
cargo.set("outPrice", new
Double(23.8));
System.out.println("name: " + cargo.get("name"));
System.out.println("inPrice: " +
cargo.get("inPrice"));
System.out.println("outPrice: " +
cargo.get("outPrice"));
System.out.println();
上述代码运行结果如下:
以上代码简单说明了一下BeanUtils常见的基本用法,还有很多高阶或者更具体的应用及原理,这里无法一一讲到,而且有很多笔者也不熟悉、不了解,对BeanUtils的讲解就到此吧。如果你有兴趣,或者还不是很清楚为什么像这样动态的或者说松散的访问JavaBean是有必要的,可以把Struts的源码拿下来研究一下,看看FormBean以及DynaActionForm这些是如何被动态创建的,一定会有收获。
Collections,又是一个重量级的东西,为Java标准的Collections
API提供了相当好的补充。我不知道其他人,就我自己而言,让我用java.util.Collection及其子类,加上java.util.Collections类
提供的操作方法,处理一些简单的数据结构问题还可以,稍微复杂一点的就觉得有点头痛,很多细节的地方需要我插入这样那样的小逻辑,或者感觉它太死板,不够灵活,再或者确实有点晦涩吧。再说了,如果我只是处理一般的数据结构问题,为什么不自己用数组或者自定义的链表来做,再加上Jakarta
Commons的Lang提供的ArrayUtils、StringUtils等,已经基本够了,性能可以保证,那么还要这个Collections
API干嘛。当然,说到这里有些偏激了,Collections当然有它存在的道理,能够把常用的数据结构归纳起来,以通用的方式去维护和访问,这应该说是一种进步,但是用起来似乎不够友好。这个时候我就会想,如果Java比现在做得更好用些,或者有一套第三方的API把我的这些需求抽象出来,实现了,该多好。Commons
Collections就是这样一套API。
在这里可以找到下载链接:(binary和src都有)
目前Commons
Collection发布的最新版本是3.1。建议下载这个3.1版本,页面上出现的2.1.1是针对2.1不兼容3.0而发布的升级维护版。
我们先来浏览一下它的包结构。一共是12个:
Collections API的朋友大概或多或少会同意我如下的划分:在Java的Collections
API中,不狭义的区分语法上的接口和类,把它们都看作是类的话,大致我们可以发现三种主要的类别:
容器类:如Collection、List、Map等,用于存放对象和进行简单操作的;
操作类:如Collections、Arrays等,用于对容器类的实例进行相对复杂操作如排序等;
辅助类:如Iterator、Comparator等,用于辅助操作类以及外部调用代码实现对容器类的操作,所谓辅助,概括而通俗的来讲,就是这些类提供一种算法,你给它一个对象或者一组对象,或者仅仅是按一定的规则调用它,它给你一个运算后的答案,帮助你正确处理容器对象。比如Iterator会告诉你容器中下一个对象有没有、是什么,而Comparator将对象大小/先后次序的算法逻辑独立出来。
同样,Jakarta
Commons Collections我们细细看来,也能够找出类似的划分:
作为容器类的补充,我们可以找到Bag、Buffer、BidiMap、OrderedMap等等;
作为操作类的补充,我们可以找到CollectionUtils、IteratorUtils、ListUtils、SetUtils等等;
作为辅助类的补充,我们可以找到MapIterator、Closure、Predicate、Transformer等等;
对于这样的一个大包,当然不可能一个类一个类的讲了,找一些常用的和有用的当做接下来讨论的话题吧。大概列个清单:
BlockingBuffer
BoundedFifoBuffer
PriorityBuffer
BufferUtils
CaseInsensitiveMap
TypedCollection
CollectionUtils
ReverseComparator
ComparatorChain
NullComparator
FixedOrderComparator
ComparatorUtils
AndPredicate
OrPredicate
AllPredicate
OnePredicate
NonePredicate
PredicateUtils
Transformer
ChainedTransformer
SwitchTransformer
TransformerUtils
ChainedClosure
WhileClosure
ClosureUtils
LoopingIterator
ArrayListIterator
FilterIterator
UniqueFilterIterator
IteratorUtils
总共9组,在接下来的笔记中我们一起慢慢的看。
首先来看Bag组。
Bag是在mons.collections包中定义的接口,它extends
java.util.Collection,而它的实现类都被放在下面的bag包中。之所以有这样一组类型,是因为我们有时候需要在Collection中存放多个相同对象的拷贝,并且需要很方便的取得该对象拷贝的个数。需要注意的一点是它虽然extends
Collection,但是如果真把它完全当作java.util.Collection来用会遇到语义上的问题,详细信息参考Javadoc。
HashBag是Bag接口的一个标准实现。而BagUtils提供一组static的方法让调用者获取经过不同装饰后的Bag实例。
还是举例子来看:
Book.java */
mons.lang.builder.ToStringB
mons.lang.builder.ToStringS
Book(String name, String isbn,
retailPrice) {
.retailPrice =
String toString() {
ToStringBuilder(this,
ToStringStyle.MULTI_LINE_STYLE)
.append("name", name)
.append("ISBN", isbn)
.append("retailPrice", retailPrice)
.toString();
String getIsbn() {
setIsbn(String isbn) {
String getName() {
setName(String name) {
getRetailPrice() {
setRetailPrice( retailPrice) {
.retailPrice =
BagUsage.java */
mons.collections.B
mons.collections.BagU
mons.collections.bag.HashB
mons.lang.StringU
BagUsage {
main(String[] args) {
demoBagUsage();
demoBagUsage() {
System.out.println(StringUtils.center(" demoBagUsage
", 40, "="));
// data setup
Book book1 =
Book("Refactoring Workbook", "7-", 29.8);
Book book2 =
Book("J2EE Design Patterns", "7-", 45);
Book book3 =
Book("Agile Software Development", "7-", 59);
// create a bag
Bag myBag = BagUtils.typedBag(
HashBag(), Book.);
myBag.add(book1, 360);
myBag.add(book2, 500);
myBag.add(book3, 170);
// calculations for a bag
book1.getRetailPrice();
book2.getRetailPrice();
book3.getRetailPrice();
book1Count =
myBag.getCount(book1);
book2Count =
myBag.getCount(book2);
book3Count =
myBag.getCount(book3);
totalValue = (price1 *
book1Count) + (price2 * book2Count)
&&&&&&&&&&&&&&&
+ (price3 * book3Count);
// dispaly results
System.out.println("There are " + book1Count +
" copies of "
&&&&&&&&&&&&&&&
+ book1.getName() + ".");
System.out.println("There are " + book2Count +
" copies of "
&&&&&&&&&&&&&&&
+ book2.getName() + ".");
System.out.println("There are " + book3Count +
" copies of "
&&&&&&&&&&&&&&&
+ book3.getName() + ".");
System.out.println("The total value of these books is:
" + totalValue);
System.out.println();
以下是运行结果:
需要说明的是,以上的代码仅仅为了演示如何使用Bag,实际应用不建议像这样硬编码。
来看Buffer组。
Buffer是定义在mons.collections包下面的接口,用于表示按一定顺序除去成员对象的collection如队列等。具体的实现类在mons.collections.buffer包下可以找到。
BufferUtils提供很多静态/工具方法装饰现有的Buffer实例,如将其装饰成BlockingBuffer、执行类型检查的TypedBuffer、或者不可改变的UnmodifiableBuffer等等。
最简单直接的Buffer实现类是UnboundedFifoBuffer,提供先进先出的大小可变的队列。而BoundedFifoBuffer则是对其大小进行了限制,是固定大小的先进先出队列。BlockingBuffer要在多线程的环境中才能体现出它的价值,尤其是当我们需要实现某种流水线时这个BlockingBuffer很有用:每个流水线上的组件从上游的BlockingBuffer获取数据,处理后放到下一个BlockingBuffer中依次传递。BlockingBuffer的核心特色通俗点说就是如果你向它要东西,而它暂时还没有的话,你可以一直等待直至拿到为止。PriorityBuffer则提供比一般的先进先出Buffer更强的控制力:我们可以自定义Comparator给它,告诉它怎么判定它的成员的先后顺序,优先级最高的最先走。
为了方便和清晰的需要,我在这里只举一个BoundedFifoBuffer,包装成TypedBuffer,看看在具体的代码中通常如何使用Buffer:(还是沿用上次的Book类)
java.util.I
mons.collections.B
mons.collections.BufferU
mons.collections.buffer.BoundedFifoB
mons.lang.StringU
BufferUsage {
main(String[] args) {
demoBufferUsage();
demoBufferUsage() {
System.out.println(StringUtils.center(" demoBagUsage
", 40, "="));
// data setup
Book book1 =
Book("Refactoring Workbook", "7-", 29.8);
Book book2 =
Book("J2EE Design Patterns", "7-", 45);
Book book3 =
Book("Agile Software Development", "7-", 59);
Book book4 =
Book("Professional JSP", "7-", 100);
// create a Buffer
Buffer buffer =
&&&&&&&&&&&
BufferUtils.typedBuffer(
BoundedFifoBuffer(3), Book.);
buffer.add(book1);
buffer.add(book2);
buffer.add(book3);
Book removed = (Book) buffer.remove();
System.out.println("Removed:");
System.out.println(removed);
buffer.add(book4);
// get items in buffer
( i = 0; i & 3; i++) {
&&&&&&&&&&&
System.out.println(buffer.get());
&&&&&&&&&&&
buffer.remove();
System.out.println(StringUtils.repeat("=",
以下是运行结果:
我们可以看到,Buffer的add和remove方法分别添加新成员和删除最先加入的成员。由于我们的Buffer定义为只能装3个Book类的实例,所以不论我们试图加入其他类型的对象,或者加入超过3个,操作都将失败。如果我们在遍历时使用get()而不调用remove(),那么我们将得到3个相同的拷贝,而这正是我们期望的FIFO队列的行为。假如你需要遍历并保留数据,可以使用标准的Iterator机制。
接下来看Map组。
Collections在java.util.Map的基础上扩展了很多接口和类,比较有代表性的是BidiMap、MultiMap和LazyMap。跟Bag和Buffer类似,Commons
Collections也提供了一个MapUtils。
所谓BidiMap,直译就是双向Map,可以通过key找到value,也可以通过value找到key,这在我们日常的代码-名称匹配的时候很方便:因为我们除了需要通过代码找到名称之外,往往也需要处理用户输入的名称,然后获取其代码。需要注意的是BidiMap当中不光key不能重复,value也不可以。
所谓MultiMap,就是说一个key不在是简单的指向一个对象,而是一组对象,add()和remove()的时候跟普通的Map无异,只是在get()时返回一个Collection,利用MultiMap,我们就可以很方便的往一个key上放数量不定的对象,也就实现了一对多。
所谓LazyMap,意思就是这个Map中的键/值对一开始并不存在,当被调用到时才创建,这样的解释初听上去是不是有点不可思议?这样的LazyMap有用吗?我们这样来理解:我们需要一个Map,但是由于创建成员的方法很“重”(比如数据库访问),或者我们只有在调用get()时才知道如何创建,或者Map中出现的可能性很多很多,我们无法在get()之前添加所有可能出现的键/值对,或者任何其它解释得通的原因,我们觉得没有必要去初始化一个Map而又希望它可以在必要时自动处理数据生成的话,LazyMap就变得很有用了。
我们还是通过一个具体的例子来说明:
java.util.D
java.util.HashM
java.util.M
mons.collections.BidiM
mons.collections.F
mons.collections.MultiHashM
mons.collections.MultiM
mons.collections.bidimap.DualHashBidiM
mons.collections.map.LazyM
mons.lang.StringU
MapUsage {
main(String[] args) {
demoBidiMap();
demoMultiMap();
demoLazyMap();
demoBidiMap() {
System.out.println(StringUtils.center(" demoBidiMap
", 40, "="));
BidiMap bidiMap =
DualHashBidiMap();
bidiMap.put("BJ", "Beijing");
bidiMap.put("SH", "Shanghai");
bidiMap.put("GZ", "Guangzhou");
bidiMap.put("CD", "Chengdu");
System.out.println("Key-Value: BJ = " +
bidiMap.get("BJ"));
System.out.println("Value-Key: Chengdu = " + bidiMap.getKey("Chengdu"));
System.out.println(StringUtils.repeat("=",
demoMultiMap() {
System.out.println(StringUtils.center(" demoMultiMap
", 40, "="));
MultiMap multiMap =
MultiHashMap();
multiMap.put("Sean", "C/C++");
multiMap.put("Sean", "OO");
multiMap.put("Sean", "Java");
multiMap.put("Sean", ".NET");
multiMap.remove("Sean", "C/C++");
System.out.println("Sean's skill set: " +
multiMap.get("Sean"));
System.out.println(StringUtils.repeat("=",
demoLazyMap() {
System.out.println(StringUtils.center(" demoLazyMap
", 40, "="));
// borrowed from Commons Collection's Javadoc
Factory factory =
&&&&&&&&&&&
Object create() {
&&&&&&&&&&&&&&&
&&&&&&&&&&&
Map lazy = LazyMap.decorate(
HashMap(), factory);
System.out.println(lazy.get("NOW"));
System.out.println(StringUtils.repeat("=",
以下是运行结果:
简单说一下这个Factory,它是定义在mons.collections包下面的一个接口,用于自定义对象的创建过程。这个有点像是后面我们要讲的Transformer的简化版本,但是也更直接也很好用,至少Commons
Collections通过它向开发人员开放了一个可以方便控制对象创建细节的接口。
接下来看看Collection组。
首先就是这个TypedCollection,它实际上的作用就是提供一个decorate方法,我们传进去一个Collection和需要的类型甄别信息java.lang.Class,它给我们创建一个全新的强类型的Collection。我们其实在bag、buffer、list、map、set这些子包中都可以找到分别对应Bag、Buffer、List、Map、Set接口的TypedXxxx版本。
方法签名:
Collection decorate(Collection
coll, Class type)
当它执行时,它会判断coll是否为null,同时如果coll包含数据,它会对数据进行验证,看是否满足指定的type条件。最后它返回一个强类型的Collection,当我们对这个强类型的Collection进行add操作时,它会帮我们确保添加的是正确的类型。
而这个CollectionUtils可能大家都已经想到了,就是提供一组针对Collection操作的工具/静态方法。比较有意思的是对Collection的转型、合并、减等操作。
由于这两个类的功能和作用都比较清晰,我就不举例说明了,需要进一步了解的请看Javadoc。
接下来我们会讲到辅助类,首先看Comparator组。
其实Comparator这个概念并不是Commons
Collections引入的,在标准的Java
Collections API中,已经明确定了一个parator接口,只是有很多人并不了解,Commons
Collections也只是扩展了这个接口而已。这个parator定义如下核心方法:
compare(Object arg0, Object
传给它两个对象,它要告诉我们这两个对象哪一个在特定的语义下更“大”,或者两者相等。如果arg0
& arg1,返回大于0的整数;如果arg0
= arg1,返回0;如果arg0
& arg2,返回小于0的整数。
我们看看Commons
Collections给我们提供了哪些Comparator的实现类(都在parators包下面):
有关Transformer的内容会在以后的笔记中讲到。
以上除了ComparatorChain之外,似乎都是实现一些很基本的比较方法,但是当我们用ComparatorChain将一组Comparator串起来之后,就可以实现非常灵活的比较操作。那么这些Comparator在实际代码中如何使用呢?看例子:
Issue.java */
mons.lang.builder.ToStringB
mons.lang.builder.ToStringS
Issue( id, String severity, String owner)
.severity =
String toString() {
ToStringBuilder(,
ToStringStyle.SHORT_PREFIX_STYLE)
&&&&&&&&&&&&&&&
.append("id", id)
&&&&&&&&&&&&&&&
.append("severity", severity)
&&&&&&&&&&&&&&&
.append("owner", owner)
&&&&&&&&&&&&&&&
.toString();
setId( id) {
String getOwner() {
setOwner(String owner) {
String getSeverity()
setSeverity(String severity) {
.severity =
ComparatorUsage.java */
java.util.A
mons.beanutils.BeanC
parators.FixedOrderC
mons.lang.StringU
ComparatorUsage {
main(String[] args) {
demoComparator();
demoComparator() {
System.out.println(StringUtils.center(" demoComparator
", 40, "="));
// data setup
Issue[] issues =
&&&&&&&&&&&&&&&
Issue(15102, "Major", "John"),
&&&&&&&&&&&&&&&
Issue(15103, "Minor", "Agnes"),
&&&&&&&&&&&&&&&
Issue(15104, "Critical", "Bill"),
&&&&&&&&&&&&&&&
Issue(15105, "Major", "John"),
&&&&&&&&&&&&&&&
Issue(15106, "Major", "John"),
&&&&&&&&&&&&&&&
Issue(15107, "Critical", "John"),
&&&&&&&&&&&&&&&
Issue(15108, "Major", "Agnes"),
&&&&&&&&&&&&&&&
Issue(15109, "Minor", "Julie"),
&&&&&&&&&&&&&&&
Issue(15110, "Major", "Mary"),
&&&&&&&&&&&&&&&
Issue(15111, "Enhancement", "Bill"),
&&&&&&&&&&&&&&&
Issue(15112, "Minor", "Julie"),
&&&&&&&&&&&&&&&
Issue(15113, "Major", "Julie")
// comparators setup
String[] severityOrder = {"Critical", "Major", "Minor",
"Enhancement"};
Comparator severityComparator =
FixedOrderComparator(severityOrder);
ComparatorChain compChain =
ComparatorChain();
compChain.addComparator(new BeanComparator("owner"));
compChain.addComparator(new BeanComparator("severity", severityComparator));
compChain.addComparator(new BeanComparator("id"));
// sort and display
Arrays.sort(issues, compChain);
( i = 0; i & issues. i++)
&&&&&&&&&&&
System.out.println(issues[i]);
System.out.println(StringUtils.repeat("=",
输出结果为:
我们可以看到,ComparatorChain中的Comparator被依次执行,先按name,再按我们自定义的severity次序,再按id,最终我们得到了重新排列的数组。
接下来看Predicate组
Predicate是Commons
Collections中定义的一个接口,可以在mons.collections包中找到。其中定义的方法签名如下:
evaluate(Object
它以一个Object对象为参数,处理后返回一个boolean值,检验某个对象是否满足某个条件。其实这个Predicate以及上一篇笔记提到的Comparator还有我们即将看到的Transformer和Closure等都有些类似C/C++中的函数指针,它们都只是提供简单而明确定义的函数功能而已。
跟其他组类似,Commons
Collections也提供了一组定义好的Predicate类供我们使用,这些类都放在mons.collections.functors包中。当然,我们也可以自定义Predicate,只要实现这个Predicate接口即可。在Commons
Collections中我们也可以很方便使用的一组预定义复合Predicate,我们提供2个或不定数量个Predicate,然后交给它,它可以帮我们处理额外的逻辑,如AndPredicate处理两个Predicate,只有当两者都返回true它才返回true;AnyPredicate处理多个Predicate,当其中一个满足就返回true,等等。
看看具体的代码中如何使用这些Predicate吧:
mons.collections.P
mons.collections.PredicateU
mons.collections.functors.InstanceofP
mons.collections.functors.NotNullP
mons.lang.BooleanU
mons.lang.StringU
PredicateUsage {
main(String[] args) {
demoPredicates();
demoPredicates() {
System.out.println(StringUtils.center(" demoPredicates
", 40, "="));
Predicate p1 =
InstanceofPredicate(String.class);
Predicate p2 = NotNullPredicate.getInstance();
Predicate p3 =
Predicate()
&&&&&&&&&&&
evaluate(Object obj) {
&&&&&&&&&&&&&&&
String str = (String)
&&&&&&&&&&&&&&&
StringUtils.isAlphanumeric(str)
&&&&&&&&&&&&&&&&&&&
&& str.length() &= 6
&&&&&&&&&&&&&&&&&&&
&& str.length() &= 10;
&&&&&&&&&&&
&&& Predicate p4 = PredicateUtils.allPredicate( Predicate[]{p1, p2, p3});&&&&&&& &&&&&&&
String input = "ABCD1234";
Object[] raw =
&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&&&&&&
"' a valid input? ",
&&&&&&&&&&&
BooleanUtils.toStringYesNo(p4.evaluate(input)),
&&&&&&&&&&&
System.out.println(StringUtils.join(raw));
System.out.println(StringUtils.repeat("=",
输出结果如下:
这里面我首先定义了3个简单的Predicate,p1判断对象是否为String的实例,p2判断是否对象为null,p3是自定义的,判断是否为数字字母的组合,并且长度在6~10字符。然后我用AllPredicate将它们组合到一起,成为p4,当p1、p2、p3都满足时,p4的evaluate方法才返回true。利用Predicate我们可以把判断true或false的逻辑从特定的业务代码分离出来,以后我们重用也好,重新组装也好,都是很方便的。
接下来看Transformer组。
我们有时候需要将某个对象转换成另一个对象供另一组方法调用,而这两类对象的类型有可能并不是出于同一个继承体系的,或者说出了很基本的Object之外没有共同的父类,或者我们根本不关心他们是不是有其他继承关系,甚至就是同一个类的实例只是对我们而言无所谓,我们为了它能够被后续的调用者有意义的识别和处理,在这样的情形,我们就可以利用Transformer。除了基本的转型Transformer之外,Commons
Collections还提供了Transformer链和带条件的Transformer,使得我们很方便的组装出有意义的转型逻辑。
假定我们在处理员工聘用时,需要将原来的Applicant对象转换为Employee对象,而Applicant类和Employee类无论继承关系、字段内容、具体业务职能等等都不是同一派系的,只是某些字段是相关的,且要求必要的转换,那么这个时候我们使用Transformer就可以比较方便的实现这项功能,并且由于它的实现是灵活的、模块化的,使得今后的维护也变得清晰和易于处理。代码如下:
Applicant.java */
mons.lang.builder.ToStringB
mons.lang.builder.ToStringS
Applicant {
String applyF
Applicant() {
Applicant(String name,
age, String applyFor) {
.applyFor = applyF
String toString() {
ToStringBuilder(,
ToStringStyle.SHORT_PREFIX_STYLE)
&&&&&&&&&&&&&&&
.append("name", name)
&&&&&&&&&&&&&&&
.append("age", age)
&&&&&&&&&&&&&&&
.append("applyFor", applyFor)
&&&&&&&&&&&&&&&
.toString();
getAge() {
setAge( age) {
String getApplyFor()
setApplyFor(String applyFor) {
.applyFor = applyF
String getName() {
setName(String name) {
Employee.java */
java.util.D
mons.lang.builder.ToStringB
mons.lang.builder.ToStringS
mons.lang.time.DateFormatU
Employee {
Date dateJ
Employee() {
Employee(String name,
age, Date dateJoined, String grade,
.dateJoined =
String toString() {
ToStringBuilder(,
ToStringStyle.SHORT_PREFIX_STYLE)
&&&&&&&&&&&&&&&
.append("name", name)
&&&&&&&&&&&&&&&
.append("age", age)
&&&&&&&&&&&&&&&
.append("dateJoined",
DateFormatUtils.format(dateJoined, "yyyy-MM-dd"))
&&&&&&&&&&&&&&&
.append("grade", grade)
&&&&&&&&&&&&&&&
.append("salary", salary)
&&&&&&&&&&&&&&&
.toString();
getAge() {
setAge( age) {
Date getDateJoined()
setDateJoined(Date dateJoined) {
.dateJoined =
String getGrade() {
setGrade(String grade) {
String getName() {
setName(String name) {
getSalary() {
setSalary( salary) {
TransformerUsage.java */
java.util.A
java.util.C
java.util.D
java.util.I
java.util.L
mons.collections.CollectionU
mons.collections.P
mons.collections.T
mons.collections.functors.SwitchT
mons.lang.StringU
TransformerUsage {
main(String[] args) {
demoTransformerUsage();
demoTransformerUsage() {
System.out.println(StringUtils.center("
demoTransformerUsage ", 40, "="));
// data setup
Applicant[] applicants =
Applicant[]
&&&&&&&&&&&
Applicant("Tony", 26, "Developer"),
&&&&&&&&&&&
Applicant("Michelle", 24, "Tester"),
&&&&&&&&&&&
Applicant("Jack", 28, "Project
List appList = Arrays.asList(applicants);
// predicate setup
Predicate isDeveloper =
Predicate()
&&&&&&&&&&&
evaluate(Object obj) {
&&&&&&&&&&&&&&&
Applicant app = (Applicant)
&&&&&&&&&&&&&&&
"Developer".equalsIgnoreCase(app.getApplyFor());
&&&&&&&&&&&
Predicate isTester =
Predicate()
&&&&&&&&&&&
evaluate(Object obj) {
&&&&&&&&&&&&&&&
Applicant app = (Applicant)
&&&&&&&&&&&&&&&
"Tester".equalsIgnoreCase(app.getApplyFor());
Predicate isPM =
Predicate()
&&&&&&&&&&&
evaluate(Object obj) {
&&&&&&&&&&&&&&&
Applicant app = (Applicant)
&&&&&&&&&&&&&&&
Manager".equalsIgnoreCase(app.getApplyFor());
&&&&&&&&&&&
Predicate[] checkApplyFor =
Predicate[] {
&&&&&&&&&&&
isDeveloper,
&&&&&&&&&&&
&&&&&&&&&&&
// transformer setup
Transformer developerTransformer =
Transformer() {
&&&&&&&&&&&
Object transform(Object obj)
&&&&&&&&&&&&&&&
Applicant app = (Applicant)
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
app.getName(), app.getAge(),
"E4", 2000
&&&&&&&&&&&&&&&
&&&&&&&&&&&
Transformer testerTransformer =
Transformer() {
&&&&&&&&&&&
Object transform(Object obj)
&&&&&&&&&&&&&&&
Applicant app = (Applicant)
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
app.getName(), app.getAge(),
"E4", 2000
&&&&&&&&&&&&&&&
&&&&&&&&&&&
Transformer pmTransformer =
Transformer() {
&&&&&&&&&&&
Object transform(Object obj)
&&&&&&&&&&&&&&&
Applicant app = (Applicant)
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
app.getName(), app.getAge(),
"E5", 3000
&&&&&&&&&&&&&&&
&&&&&&&&&&&
Transformer[] transformers =
Transformer[] {
&&&&&&&&&&&
developerTransformer,
&&&&&&&&&&&
testerTransformer,
&&&&&&&&&&&
pmTransformer
// transform
Transformer employTransformer =
SwitchTransformer(
&&&&&&&&&&&
checkApplyFor, transformers, null
Collection employed = CollectionUtils.collect(appList,
employTransformer);
System.out.println("Applicants: ");
Iterator iter1 = appList.iterator();
while (iter1.hasNext()) {
&&&&&&&&&&&
System.out.println(iter1.next());
System.out.println("Employed: ");
Iterator iter2 = employed.iterator();
while (iter2.hasNext()) {
&&&&&&&&&&&
System.out.println(iter2.next());
System.out.println(StringUtils.repeat("=",
以下是运行结果:
我们首先定义一组Predicate,用于在SwitchTransformer中判断采用那个具体的Transformer,这个具体的Transformer也是通过数组同时传递给SwitchTransformer的构造方法的。不同的Predicate可以有不同的实现,不同的Transformer也可以有不同的实现,因为它们之间实际上完全是相互独立的。这就使我们有效的分离了逻辑和具体业务。
接下来看Closure组。
Closure这一组接口和类提供一个操作对象的execute方法,为我们在处理一系列对象时可以将处理逻辑分离出来。理论上讲,使用Transformer也可以达到类似的效果,只要输出对象和输入对象是同一个对象就好,但是Closure接口定义的execute方法返回void,并且从效果和功能区分上,Closure可以更好的诠释对象处理或执行的意思。而事实上,ClosureUtils中也提供了一个asClosure方法包装一个现成的Transformer。
沿用前面的Emploee类,我们来给一组员工涨工资:
java.util.A
java.util.C
java.util.D
java.util.I
mons.collections.C
mons.collections.CollectionU
mons.lang.StringU
ClosureUsage {
main(String[] args) {
demoClosureUsage();
demoClosureUsage() {
System.out.println(StringUtils.center("
demoClosureUsage ", 40,
// data setup
Employee[] employees =
Employee[]
&&&&&&&&&&&
Employee("Tony", 26, new Date(), "E4", 2000),
&&&&&&&&&&&
Employee("Michelle", 24, new Date(), "E4", 2000),
&&&&&&&&&&&
Employee("Jack", 28, new Date(), "E5", 3000)
Collection empColl = Arrays.asList(employees);
printColl("Before salary increase:",
// closure setup
Closure salaryIncreaseClosure =
Closure() {
&&&&&&&&&&&
execute(Object obj) {
&&&&&&&&&&&&&&&
Employee emp = (Employee)
&&&&&&&&&&&&&&&
emp.setSalary(emp.getSalary() * 1.20);
&&&&&&&&&&&
// salary increase
CollectionUtils.forAllDo(empColl, salaryIncreaseClosure);
printColl("After salary increase:",
System.out.println(StringUtils.repeat("=",
printColl(String label, Collection c)
if (StringUtils.isNotBlank(label)) {
&&&&&&&&&&&
System.out.println(label);
Iterator iter = c.iterator();
(iter.hasNext()) {
&&&&&&&&&&&
System.out.println(iter.next());
以下是运行结果:
我这里举的是一个相对简单的例子,在Closure这一组还有一些很方便的类,如ChainedClosure可以包装一组Closure作为整体执行;IfClosure在创建时需要提供给它一个Predicate和两个Closure,执行时先做Predicate判定再决定执行哪一个Closure;SwitchClosure跟SwitchTransformer类似,根据创建时传入的Predicate组和Closure组对应执行;WhileClosure则根据创建时传入的Predicate做判断,如果为true则执行Closure,直到Predicate返回false;等等。
具体用法请参考Javadoc。
来看最后一组
– Iterator。
java.util.Iterator接口定义了标准的Collection遍历方法,但是如果不做改变的使用它,我们得到的是从头到尾一次性的遍历。假如我们需要循环遍历,假如我们需要遍历某一段,假如我们需要遍历满足某些条件的元素,等等等等,我们就不能完全依赖于这个Iterator的标准实现了。除非我们宁可在此基础上在调用的代码中多加一些判断,不过这样的话代码就会显得混乱,时间长了就容易变得难以维护。Commons
Collections的这一组Iterator为我们带来了便利。
这些Iterator使用都很一目了然,直接看例子吧:
java.util.A
java.util.I
java.util.L
mons.collections.P
mons.collections.iterators.ArrayListI
mons.collections.iterators.FilterI
mons.collections.iterators.LoopingI
mons.lang.StringU
IteratorUsage {
main(String[] args) {
demoIteratorUsage();
void demoIteratorUsage() {
System.out.println(StringUtils.center("
demoClosureUsage ", 40, "="));
// data setup
String[] weekDays = {
&&&&&&&&&&&
"Monday", "Tuesday", "Wednesday",
&&&&&&&&&&&
"Thursday", "Friday", "Saturday", "Sunday"
List weekDayList = Arrays.asList(weekDays);
// workdays
Iterator iter1 =
ArrayListIterator(weekDays, 0, 5);
printColl("Partial:", iter1, 5);
Iterator iter2 =
LoopingIterator(weekDayList);
printColl("Loop:", iter2, 10);
// looping workdays
Predicate notWeekendPredicate =
Predicate() {
&&&&&&&&&&&
evaluate(Object obj) {
&&&&&&&&&&&&&&&
String str = (String)
&&&&&&&&&&&&&&&
("Saturday".equalsIgnoreCase(str)) {
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
("Sunday".equalsIgnoreCase(str)) {
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&
Iterator iter3 =
FilterIterator(
&&&&&&&&&&&
LoopingIterator(weekDayList),
&&&&&&&&&&&
notWeekendPredicate
printColl("No Weekends loop:", iter3,
System.out.println(StringUtils.repeat("=",
printColl(String label, Iterator iter,
maxCount) {
(StringUtils.isNotBlank(label))
&&&&&&&&&&&
System.out.println(label);
(iter.hasNext() && i &
maxCount) {
&&&&&&&&&&&
System.out.println("# " + iter.next() + " #");
&&&&&&&&&&&
运行结果如下:
有了这些实用的Iterator类,我们就可以轻松的实现可配置的遍历行为了。
在前面的随笔中,我们一起过了一遍Jakarta
Commons这个类库中非常重要的三个子项目:Commons
Lang、Commons
BeanUtils和Commons
Collections,这些工具包在无数开源或商业框架中都可以找到,可以说应用范围非常广。
当然,Jakarta
Commons提供的API远不止我们提到的这些,除了上述三个核心项目之外,还有读取和映射XML文档的Digester/Betwixt、处理命令行参数的CLI、提供常用编码算法的Codec、用于读取多种格式的配置文件的Configuration、发送电子邮件的Email、上传文件的FileUpload、模拟HTTP客户端的HttpClient、处理日志的Logging等等等等,实在是相当的丰富。
Commons官网上可以找到完整的组件列表:
今后如果发现特别有价值需要跟大家分享的,我还会贴出来,只是不会像这样有条理和规律了。希望我的这一组笔记对大家了解和认识Jakarta
Commons有所帮助,也希望这些优秀的类库及其源码能够给大家带来工作效率和编程功底上的提升。
我整理了一份清单,列出了所有这一系列随笔的链接,方便大家查找和阅读:
阅读(...) 评论()

我要回帖

更多关于 文化产业包含哪些 的文章

 

随机推荐