<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>且听书吟</title>
        <link>https://stage.yufan.me</link>
        <description>诗与梦想的远方</description>
        <lastBuildDate>Sat, 09 May 2026 10:27:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>WordPress 3.2.1</generator>
        <language>zh-CN</language>
        <image>
            <title>且听书吟</title>
            <url>https://stage.yufan.me/logo.svg</url>
            <link>https://stage.yufan.me</link>
        </image>
        <copyright>All rights reserved 2011, 雨帆</copyright>
        <category>文章</category>
        <category>杂思</category>
        <category>杂谈</category>
        <category>编程</category>
        <category>笔记</category>
        <category>小说</category>
        <atom:link href="https://stage.yufan.me/tags/thinking/feed" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[当图书差错成为常态]]></title>
            <link>https://stage.yufan.me/posts/when-book-quality-slips</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/when-book-quality-slips</guid>
            <pubDate>Mon, 29 Dec 2025 12:12:42 GMT</pubDate>
            <description><![CDATA[当下的出版业基本已经可以定性为夕阳产业，图书编辑长期被视为成本部门，对他们的要求其实只有一项：只要符合质量标准即可。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2025/12/2025122302110200.jpg"/><link rel="preload" as="image" href="https://cat.yufan.me/images/2025/12/2025123001510800.jpg"/><img src="https://cat.yufan.me/images/2025/12/2025122302110200.jpg" alt="书房一隅"/>
<div class="mt-5 mb-5.5 max-w-87.5 max-xl:mx-auto max-md:mx-0 max-md:mt-0 max-md:mb-5 max-md:max-w-full"><div class="aplayer" data-id="aagxny03ywvt9xt1"></div></div>
<p>最近在 B 站刷到一位北京语文老师抨击上海古籍出版社《西厢记》存在数百处错误的视频。随后，又陆续看到多位 UP 主针对上海古籍出版社某些书籍中的个别差错进行“逐条批评”的内容。对此，我的看法是：<strong>大可不必如此上纲上线</strong>。</p>
<p>如果将视角稍稍拉远，就会发现，当下的出版业基本已可视为一个夕阳产业。在出版社内部，图书编辑长期被视为成本部门，对其工作的核心要求往往只有一条：<strong>只要符合质量标准即可</strong><sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup>。</p>
<p>而目前通行的图书质量检验标准是：整本书的差错率需控制在万分之一以下。只要达到这一标准，图书便被认定为质量合格，可以正常出版发行。该标准主要涵盖三类问题：其一，也是最重要的，是意识形态<sup><a href="#user-content-fn-2" id="user-content-fnref-2" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup>问题<sup><a href="#user-content-fn-3" id="user-content-fnref-3" data-footnote-ref="true" aria-describedby="footnote-label">3</a></sup>；其二，是错别字、病句、标点符号等文字层面的差错；其三，是知识性与逻辑性方面的错误。不同类型的问题有不同的统计与容忍尺度，其中意识形态问题属于红线，不允许出现。如果出现有关意识形态的问题，轻则召唤销毁全部已售图书，重则不再下发新书号。</p>
<p>换言之，一本书在出版后仍然存在一定数量的错误，在制度层面事实上是被默认、被容忍的。较为负责任的出版社，通常会采用“三审三校”<sup><a href="#user-content-fn-4" id="user-content-fnref-4" data-footnote-ref="true" aria-describedby="footnote-label">4</a></sup>的流程，并配有专门的质量管理部门进行不定期随机图书抽检，以期尽可能降低出版物中的差错率。但也有不少出版社采取“以量取胜”的策略（如清华大学出版社），更看重年度出版码洋，而非单本图书的质量。</p>
<p>在这种背景下，为了维持持续而快速的出书节奏，在有限的编辑人员编制之下，<strong>留给编辑逐字核对的时间本就极为有限</strong>，要求其修正全部差错，几乎是不可能完成的任务。尤其是在近几年图书市场持续走低的情况下，这一问题只会进一步恶化。</p>
<p>如果回顾早期的出版史，在铅字排版时代，一部作品在首版首印中已经存在的错误，即便后来多次加印，往往也不会被修正，因为书版一旦固定，改动成本极高。而在如今的电脑制版环境下，再加上“加印也需重新呈缴”<sup><a href="#user-content-fn-5" id="user-content-fnref-5" data-footnote-ref="true" aria-describedby="footnote-label">5</a></sup>的制度背景，每一次加印几乎都相当于重新制版，既有差错理论上都有机会在后续印次中得到修正。</p>
<p>因此，一般而言，<strong>同一书目越往后的印次，错误往往越少</strong>。</p>
<p>但问题在于，现实中并非所有出版社都真正落实了这一机制。不少出版社的质量管理部门形同虚设，只重视发行部门的业绩，对编辑部门的工作状态与修订反馈并不关心。结果是，即便读者将差错反馈给具体编辑，这些问题也未必会在后续加印中得到修正。</p>
<p>这也是为什么在购书时，人们常常建议优先选择“大出版社”——并非因为它们从不出错，而是其质量管理体系相对完善，更有可能避免明显低劣的出版物。</p>
<p>遗憾的是，这一经验在古籍出版领域并不完全适用。事实上，在上海古籍出版社相关事件发酵之前，我就已经明显感受到这一领域的图书质量正在快速下滑。例如，中华书局于 2019 年出版的《梁佩兰集校注》，便因质量问题遭到大量读者批评，最终被下架处理<sup><a href="#user-content-fn-6" id="user-content-fnref-6" data-footnote-ref="true" aria-describedby="footnote-label">6</a></sup>。</p>
<p>更值得注意的是，中华书局近年来重印的不少古籍，仍然沿用上世纪的铅字书版，而未重新制版。这直接导致新近印次中字迹模糊、版面老化，阅读体验极差。在古籍领域，许多所谓“精校”的简体排印本，在阅读体验和文本可靠性上，反而不如直接阅读影印底本，甚至不如一些带有题跋、校勘痕迹的旧本。</p>
<p>即将于 2026 年 1 月 1 日施行的<a href="http://www.npc.gov.cn/npc/c2/c30834/202512/t20251227_450731.html" rel="nofollow" target="_blank">《中华人民共和国国家通用语言文字法》</a>，在相关条款中明确提出：中文出版物应当符合国家通用语言文字的规范和标准。这基本限定了未来出版图书只能以《通用规范汉字表》<sup><a href="#user-content-fn-7" id="user-content-fnref-7" data-footnote-ref="true" aria-describedby="footnote-label">7</a></sup>所圈定的规范汉字进行排印<sup><a href="#user-content-fn-8" id="user-content-fnref-8" data-footnote-ref="true" aria-describedby="footnote-label">8</a></sup>。</p>
<p>当然，法律也为文物古迹、姓氏、书法篆刻、题词招牌，以及出版、教学、研究确有需要的情形，保留了有限使用繁体字、异体字的空间。这种看似克制的规定，恰恰反映出立法者所面对的两难处境：一方面，需要维护国家通用语言文字的统一性与规范性；另一方面，又不得不承认，在学术、历史与文化传承领域，语言文字从来不是一个可以被简单“标准化”的对象。</p>
<p>问题也正出在这里。法律能够规定“能不能用”，却很难解决“用得好不好”。在古籍出版中，是否使用规范汉字表外的繁体字、异体字，本质上并非技术问题，而是<strong>编辑能力、学术判断与责任意识</strong>的问题。如果编辑团队本身缺乏相应训练与时间保障，那么即便法律允许，现实中也可能被简单粗暴地“一刀切”式简化；而所谓的“规范”，最终只剩下形式上的合规，而非文本意义上的准确。</p>
<p>更何况，《通用规范汉字表》颁布已逾十年，但仍有大量异体字未被扶正<sup><a href="#user-content-fn-9" id="user-content-fnref-9" data-footnote-ref="true" aria-describedby="footnote-label">9</a></sup>。很多情况下，若单纯追求形式统一，反而会造成新的错谬，使古籍的理解更加困难。</p>
<p>从这个角度看，图书差错之所以逐渐成为一种“常态”，并不只是因为某一家出版社、某一套制度出了问题，而是因为整个出版体系正在被迫向<strong>最低成本、最低责任</strong>的方向滑落。法律可以为文字的边界划线，却无法替代专业判断；制度可以要求“符合标准”，却无法强制生成真正的敬畏与耐心。</p>
<p>或许，真正令人担忧的，并不是我们是否还能读到一部“零差错”的书，而是当下一代读者逐渐失去辨认、理解古籍原貌的能力时，是否还会意识到：那些被省略、被简化、被误读的地方，原本曾经承载着更为复杂、精细的思想世界。2023 年新春贺岁片《满江红》在宣发中，将“髪”误写为“發”的海报错误，或许并非孤例，而只是一个预兆。</p>
<p>如果说这是一种悲哀，那么它恐怕并不只属于出版业。</p>
<img src="https://cat.yufan.me/images/2025/12/2025123001510800.jpg" alt="竹影茶香好读书"/>
<section data-footnotes="true" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes<a href="#footnote-label"><span class="icon icon-link"></span></a></h2>
<ol>
<li id="user-content-fn-1">
<p>责任编辑工作只做到<a href="https://mp.weixin.qq.com/s/kHeECKy6rAlEqUaiBlXf4A" rel="nofollow" target="_blank">符合工作最低要求</a>的程度是普遍现象。 <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-2">
<p>在中国大陆语境下，通常特指：坚持马克思主义的指导地位和中国特色社会主义道路；反对历史虚无主义、西方“西化”思潮以及极端个人主义等资本主义思想；维护国家认同感和中国共产党领导地位。 <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-3">
<p>在出版语境下，通常特指：宣传与中国共产党、中华人民共和国以及中华民族的政治目标和社会价值取向相背离的意识形态，尤其是对前苏联的“抹黑”。 <a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-4">
<p><a href="https://mp.weixin.qq.com/s/LCQRDRjaLYKgHX97SRFyzg" rel="nofollow" target="_blank">三审三校</a>：对稿件进行三次审查和三次校对。每轮审校过程为：编辑审读修改稿件，修改结果交予作者核实；作者核对通过后，编辑交予排版人员重新排版；校对人员将排版结果对比原稿，尤其是修改过的部分（核红）。 <a href="#user-content-fnref-4" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-5">
<p><a href="https://xzfg.moj.gov.cn/front/law/detail?LawID=1745" rel="nofollow" target="_blank">出版管理条例</a> 第二十二条：出版单位应当按照国家有关规定向国家图书馆、中国版本图书馆和国务院出版行政主管部门免费送交样本。 <a href="#user-content-fnref-5" data-footnote-backref="" aria-label="Back to reference 5" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-6">
<p>澎湃新闻报导：<a href="https://www.thepaper.cn/newsDetail_forward_16076366" rel="nofollow" target="_blank">《〈梁佩兰集校注〉被指漏洞百出，中华书局：即日下架，可退可换》</a> <a href="#user-content-fnref-6" data-footnote-backref="" aria-label="Back to reference 6" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-7">
<p>社会一般应用领域的汉字使用应以<a href="https://www.gov.cn/gongbao/content/2013/content_2481095.htm" rel="nofollow" target="_blank">《通用规范汉字表》</a>为准，原有相关字表停止使用。 <a href="#user-content-fnref-7" data-footnote-backref="" aria-label="Back to reference 7" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-8">
<p>《通用规范汉字表》共收字 8105 个，一级字表为常用字集，收字 3500 个，二级字表收字 3000 个，三级字表收字 1605 个。 <a href="#user-content-fnref-8" data-footnote-backref="" aria-label="Back to reference 8" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-9">
<p>汉字简化中往往一简多繁，但在《通用规范字表》中，并未全部纳入。参阅<a href="https://zhuanlan.zhihu.com/p/50159645" rel="nofollow" target="_blank">《一表顶过去多表的〈通用规范汉字表〉有哪些缺陷？》</a>。 <a href="#user-content-fnref-9" data-footnote-backref="" aria-label="Back to reference 9" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/publish">出版</category>
            <category domain="https://stage.yufan.me/cats/gossip">杂谈</category>
            <enclosure url="https://stage.yufan.me/images/og/when-book-quality-slips.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[学会向这个世界妥协]]></title>
            <link>https://stage.yufan.me/posts/living-with-noise</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/living-with-noise</guid>
            <pubDate>Sun, 28 Sep 2025 15:58:28 GMT</pubDate>
            <description><![CDATA[学会妥协，并不是承认错误，而是承认世界不会完全如你所愿。与世界相处的方式，往往不是“打败”，而是“放下”。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2025/09/2025092900210300.jpg"/><link rel="preload" as="image" href="https://cat.yufan.me/images/2025/09/2025092900183100.jpg"/><img src="https://cat.yufan.me/images/2025/09/2025092900210300.jpg" alt="藍切 健さんオリジナル２曲描き下ろし！！ - inika"/>
<div class="mt-5 mb-5.5 max-w-87.5 max-xl:mx-auto max-md:mx-0 max-md:mt-0 max-md:mb-5 max-md:max-w-full"><div class="aplayer" data-id="y5avhbh1vx8rslm1"></div></div>
<p>9 月初，我发了一个关于《围城》的段子。评论区毫不意外地迎来了一阵骂声，言辞犀利，仿佛和我有不共戴天之仇。一如年初我提到京台高速时，解释“台”指的是台湾，也同样被人群起而攻之。</p>
<p>互联网时代最显著的特点，就是“放大”。原本小众的亚文化，可能因为传播而进入主流；细微的声音，也可能瞬间成为热梗。与此同时，各种铺天盖地的杂声也被无限放大，几乎每一次发声都可能引发涟漪——有时是赞扬，有时则是苛责。</p>
<p>记得大学时，我常读阮一峰老师的博客，经常能发现文章里的小错误。评论区里总有人指正，也有人冷嘲热讽。阮老师的处理方式很特别：修正错误，但不删评论。当时我并不理解，觉得刺眼的言论删掉就好。我曾深信“美国式的言论自由”：你有“挥拳头”的权利，我也有“不被打”的权利。</p>
<p>然而，网络里的冷暴力因为传播而被放大，锋利得像刀，很容易伤人。年轻时的我常常咽不下这口气，总觉得一定要争个你死我活，即便争论落了下风，也会像阿 Q 一样，在心里默念自己“被儿子骂了”。2015 年，我在知乎混迹时，知乎推出过“友善度”系统，提醒大家不要过度攻击他人。可即便如此，我仍常因争论而与他人冲突，友善度一度降到最低。</p>
<p>如今回头看，那些争吵、执拗和愤怒，大多没有意义。你删不完评论，也赢不了所有的辩论。学会妥协，并不是承认错误，而是承认世界不会完全如你所愿。与世界相处的方式，往往不是“打败”，而是“放下”。</p>
<p>学会放下，并非软弱，而是一种智慧。它让你在面对网络的喧嚣时，依然能保持内心的宁静；它让你在生活的纷扰中，不再因小事消耗过多精力。有人说，成长就是学会和自己和解，也学会与世界和解。</p>
<img src="https://cat.yufan.me/images/2025/09/2025092900183100.jpg" alt="星と街 - naru"/>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/middle-age">中年</category>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/cats/gossip">杂谈</category>
            <enclosure url="https://stage.yufan.me/images/og/living-with-noise.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[編碼三境界]]></title>
            <link>https://stage.yufan.me/posts/three-stage-of-programming</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/three-stage-of-programming</guid>
            <pubDate>Fri, 19 Jan 2018 01:20:12 GMT</pubDate>
            <description><![CDATA[很多人停留在第一階段，也就是能寫出來，能用。但是代碼邏輯不精簡，質量一般，同時雜亂無章。典型的特點是寫之前毫無想法，隨想隨寫。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2019/05/2019051818123745.jpg"/><img src="https://cat.yufan.me/images/2019/05/2019051818123745.jpg" alt="Working Girl"/>
<h1 id="编码的三重境界">编码的三重境界<a href="#编码的三重境界"><span class="icon icon-link"></span></a></h1>
<p>在程序员的成长过程中，写代码的能力通常会经历三个阶段：</p>
<h3 id="1-由少写多--开始懂得写代码">1. 由少写多 —— 开始懂得写代码<a href="#1-由少写多--开始懂得写代码"><span class="icon icon-link"></span></a></h3>
<p>这个阶段的特点是“能写出来，能用”。很多人停留在这里，写的代码逻辑不够精简，质量一般，而且往往杂乱无章。典型表现是：写之前毫无规划，想到什么就写什么。虽然功能能实现，但可读性和可维护性都很差。</p>
<h3 id="2-由多写少--学会优化逻辑">2. 由多写少 —— 学会优化逻辑<a href="#2-由多写少--学会优化逻辑"><span class="icon icon-link"></span></a></h3>
<p>进入第二阶段，你会开始有意识地精简代码逻辑、优化思路。代码看起来更简洁，重复和冗余减少了。但是，这种刻意追求简洁的做法，容易带来新的问题：</p>
<ul>
<li>异常情况考虑不周全</li>
<li>可维护性下降</li>
<li>代码虽然短，但阅读困难，逻辑复杂
很多程序员在这个阶段陷入“面条代码”的陷阱：为了追求短小精悍，反而让代码变得难以理解。</li>
</ul>
<h3 id="3-由少写多--掌握抽象与设计">3. 由少写多 —— 掌握抽象与设计<a href="#3-由少写多--掌握抽象与设计"><span class="icon icon-link"></span></a></h3>
<p>第三阶段的程序员，写代码前就有清晰的需求和思路。</p>
<ul>
<li>适度抽象，考虑未来扩展</li>
<li>逻辑条理清晰，易于维护</li>
<li>不一定是最简洁的代码，但一定是最优质的代码
好的代码，重在可读性、可维护性和扩展性，而不是极致的简洁。</li>
</ul>
<hr/>
<h3 id="总结">总结<a href="#总结"><span class="icon icon-link"></span></a></h3>
<p>我发现一个有趣的现象：优秀的代码，其编程风格往往相似。写代码的关键，不在于技巧，而在于思路——你知道自己想要什么，知道要解决什么问题。</p>
<p>没有思路写出来的代码，即便再好看，也无济于事。</p>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/encoding">编码</category>
            <category domain="https://stage.yufan.me/tags/programming">编程</category>
            <category domain="https://stage.yufan.me/cats/coding">编程</category>
            <enclosure url="https://stage.yufan.me/images/og/three-stage-of-programming.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[总得给自己留下点什么]]></title>
            <link>https://stage.yufan.me/posts/leave-some-by-myself</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/leave-some-by-myself</guid>
            <pubDate>Wed, 13 Dec 2017 10:41:55 GMT</pubDate>
            <description><![CDATA[总得给自己留下点什么。我希望留下的，是那些有意思的设计思路，而不是那些「垃圾代码」。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2019/05/2019050902252161.jpg"/><link rel="preload" as="image" href="https://cat.yufan.me/images/2019/05/2019050902332168.jpg"/><img src="https://cat.yufan.me/images/2019/05/2019050902252161.jpg" alt="黄昏少女"/>
<div class="mt-5 mb-5.5 max-w-87.5 max-xl:mx-auto max-md:mx-0 max-md:mt-0 max-md:mb-5 max-md:max-w-full"><div class="aplayer" data-id="uhupj2endaqypq9p"></div></div>
<p>网易云音乐一直是一个值得吐槽的地方，比如，它常常认为你懂五国语言，动不动给你日推一些稀奇古怪的歌曲。因为我会日语，所以日推的大部分都是日文歌，还可以接受。但最近网易云音乐开始变本加厉，给我日推俄文歌，这实在是不能接受。</p>
<p>一般我熬夜时，都喜欢开着网易云音乐听歌。不是说我多喜欢音乐，而是为了防困。精力专注的时候，歌曲就像一种微噪音，你根本感知不到。有时也会听到一些不错的歌曲，就下载收藏。</p>
<p>周一时听到一首名为<a href="http://music.163.com/#/song?id=812400" rel="nofollow" target="_blank">「PLANET」</a>的歌曲，前奏就十分抓耳，当时立刻点击下载，可惜这歌竟然要付费。生在天朝，仗着自己从事 IT 相关工作，最大的好处便是能免费搞到一些数字出版物。但我在谷歌、百度上查找许久，竟找不到这首曲子的 320 Kbps 版本，不禁有些沮丧。</p>
<p>在网易的「チーズ牛丼」（沙拉牛肉）上找到一篇关于「PLANET」的创作组合 <strong>「ラムジ」</strong> 的<a href="http://music.163.com/#/topic?id=17639053" rel="nofollow" target="_blank">介绍</a>。22 岁的山下佑树在过生日时，只因想唱点什么来到东京，和报复不得施展的井上慎二郎桑如童话般在雨中相遇，并开始了长达 8 年的演艺事业。</p>
<blockquote>
<p>当時、井上慎二郎に初めて出会ったとき、雨に濡れて震える子羊のような容姿だった為、当時の山下のイメージから羊を連想し、アニメの子羊キャラクターからラムジと命名。</p>
<p>当时山下佑树遇到井上慎二郎，看到他被雨淋湿的姿态，联想到了动画《ラムヂーちゃん》里“子羊”这一角色，因而采用ラムジ作为组合名。</p>
</blockquote>
<p>一切都是那么巧合、随性，连乐队名都有这么哭笑不得的<a href="https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%A0%E3%82%B8_(%E9%9F%B3%E6%A5%BD%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88)" rel="nofollow" target="_blank">缘由</a>。然而，并非每个梦想都能瓜熟蒂落，ラムジ在 2012 年便<a href="https://www.oricon.co.jp/news/2020043/full/" rel="nofollow" target="_blank">宣布 2013 年解散</a>。我翻遍他们为数不多的专辑、单曲，喜欢上的，也只有那首「PLANET」。</p>
<p>可我还是不死心，我能感受到歌曲里那种热情和呼唤，那种渴望展露头角、被大众关注的心情。现在的我与当时的主唱山下佑树年龄相近，更能体会他期盼与绝望交织的矛盾心情。我翻遍脸书、推特及所有我所知道的社交网络，却没找到关于山下佑树的任何信息。他随着ラムジ的解散，消失在大众视野。即使是推特上，也很少有人提起。</p>
<p>可是，我还记得，就像他们的歌还在被人听、被人唱一样，我还记得这么一个乐队，如流星般存在过。</p>
<hr/>
<p>前些天翻推特，看到有人说，大部分代码的存活时间只有不到 5 年。回想自己接手过的很多老项目，确实如此。在 OneAPM 上班时，兄弟部门的系统一年重写了 2 次。自己维护的系统，也因个人审美变化，一年内留下了 3 种不同风格的代码。</p>
<p>如果说乐队的解散还能留下当时传唱的歌曲，那么程序的重写，可能就是彻底消失。那么，作为程序员，我们还能留下什么呢？</p>
<p><strong>我想，只有编程思想吧。</strong></p>
<p>记得 4 个月前带小弟写的 <a href="https://github.com/byWeaponLin/sql-generator" rel="nofollow" target="_blank">SQL Generator</a>。核心思想是对当时业务 DSL 的抽象封装，以及函数式变换思想。即使后面代码废弃，我想它的定义仍能传递给每个维护过它的人。这个设计思路再精进，便是<a href="https://pragprog.com/book/tpdsl/language-implementation-patterns" rel="nofollow" target="_blank">Language Implementation Patterns</a>中提到的解析与生成两种形态。虽然 SQL Generator 独立于底层解析器开发，但最终二者的抽象结构惊人一致。</p>
<p>同样的说法可以应用于程序设计的很多地方，比如单元测试。我以前一直不知道什么是测试、怎么写测试。后来有意识地学习模仿后发现，单测无非三大步：构造测试对象和测试数据、调用方法、断言。</p>
<p>测试对象有些可能是 Mock 的接口，但一定不能 Mock Static 对象，否则说明代码抽象存在问题。测试数据，也叫样本，关键在于能命中边界条件。而断言无非就是各种 <code>true</code>、<code>false</code>、<code>equals</code> 的判断，hamcrest 之类无非简化判断过程，但切记慎用 Mock 里的 <code>verify</code> 做断言。</p>
<p>所以，测试代码再怎么变，也逃离不了上面的编程方法，即使是别的语言，亦是如此。我很费解的是，在苏宁看到同事写测试时，竟写一个 <code>main</code> 方法，用 <code>System.out.print</code> 输出结果人肉判断。因为上线有单测覆盖率要求，他们竟写了针对实体 <code>Getter</code>、<code>Setter</code> 的测试代码。这种测试代码，有存在的意义吗？</p>
<p>有时我觉得，编程就是一种体力活：想好了怎么设计，后面的编码加测试，纯粹是一种<a href="https://zh.moegirl.org/%E7%88%86%E8%82%9D" rel="nofollow" target="_blank">肝</a>状态。有时候又觉得很多代码纯粹是套路（模板代码），只是因为某些需求不得不这么写。正如标题所言，总得给自己留下点什么。我希望留下的，是那些有意思的设计思路，而不是那些 <strong>「垃圾代码」</strong>。</p>
<img src="https://cat.yufan.me/images/2019/05/2019050902332168.jpg" alt="我的英雄学院"/>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/code">代码</category>
            <category domain="https://stage.yufan.me/cats/think">杂思</category>
            <enclosure url="https://stage.yufan.me/images/og/leave-some-by-myself.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[在编程中思考，简化你的判断逻辑]]></title>
            <link>https://stage.yufan.me/posts/rewrite-your-logic</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/rewrite-your-logic</guid>
            <pubDate>Mon, 06 Mar 2017 04:31:33 GMT</pubDate>
            <description><![CDATA[之前看 Linus Toward 在去年的某次采访中说到的好代码坏代码，当中提到了逻辑的精简，能用更通用的逻辑减少 if else 的判断在某种程度上可以使你的代码变得更好。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2019/05/2019051818210131.jpg"/><img src="https://cat.yufan.me/images/2019/05/2019051818210131.jpg" alt="在编程中思考，简化你的判断逻辑"/>
<p>之前看 Linus Toward 在去年的<a href="https://www.youtube.com/watch?v=o8NPllzkFhE&amp;feature=youtu.be&amp;t=890" rel="nofollow" target="_blank">某次采访</a>中说到的好代码坏代码，当中提到了逻辑的精简，能用更通用的逻辑减少 if else 的判断在某种程度上可以使你的代码变得更好。最近一段时间重构了部分老代码，也 Review 了不少代码，对此观点深有感触。</p>
<p>很多时候，程序员接到的需求，产品巴不得你立刻就能搞定，有时候会给非常紧迫的时间点。这种情况下会带来的最直接问题，就是<a href="http://www.ituring.com.cn/article/263057" rel="nofollow" target="_blank">“设计坏味”</a>。有整体的架构设计的不合理，也有代码逻辑的问题。尤其是对于边界条件的处理，因为需求的急，很多时候大家就会按照业务语言去写。</p>
<p>比如，下面这个例子：</p>
<p>某一报警系统产生了报警邮件，现在需要按照类型显示不同的内容。</p>
<table><thead><tr><th>类型</th><th>报警选择对象</th><th>邮件中展示内容</th></tr></thead><tbody><tr><td>Web事务</td><td>单条Web事务</td><td>Tier，Web事务，节点</td></tr><tr><td>Web事务</td><td>Tier</td><td>Tier，节点</td></tr><tr><td>节点</td><td>某一个节点</td><td>节点</td></tr><tr><td>节点</td><td>Tier</td><td>Tier，节点</td></tr></tbody></table>
<p>如果按照业务的语言，我们可能写出如下的伪代码：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-java"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Web事务</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> 单条Web事务) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier,Web事务,节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Web事务</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier,节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (节点</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> 某一个节点) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> 节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (节点</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier,节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>可能你看到这里会立刻笑出来，哪有只写 <code>if</code> 不写 <code>else</code> 的。那好，也许你会写出这样的代码。</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-java"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Web事务) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (单条Web事务) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier,Web事务,节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">else</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Tier) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier,节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">else</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (节点) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (某一个节点) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> 节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">else</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Tier) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Tier,节点;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>我相信，大部分人都能将判断逻辑写到这一层，但是，这就完了么？也许你会说完了，逻辑也正确，看起来也很清晰。然而，这远远不够。</p>
<p>其实我们可以发现，在每种情况下，都会返回 <code>节点</code> 信息。只返回节点信息的只有一种情况，其他的情况下，基本都返回 <code>Tier</code> 信息。只有 <code>Web事务 &amp;&amp; 单条Web事务</code> 的情况需要返回 <code>Web事务</code> 信息。所以，最后我们可以精简为两个判断。</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-java"><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">result </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &quot;节点&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Web事务</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> 单条Web事务) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    result </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &quot;Web事务&quot;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> +</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> result;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Web事务 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">||</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">某一个节点) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    result </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &quot;Tier&quot;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> +</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> result;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> result;</span></span></code></pre>
<p>回到最初的命题，为何不要用业务的语言来编写判断逻辑呢？因为业务语言是给用户和产品看的，他们在描述上本身就不够精简。其次，业务的描述，很多时候，是定义边界，说明问题，而不是告诉你判断逻辑。</p>
<p>所以，在写代码的时候，更多的时候要细化逻辑。这样，在维护修改时，才更为方便。下面我举另一个更具体的例子。</p>
<p>这是我 Review Scala 代码的时候遇到的一个问题，首先我先用业务语言描述一下需求。需要判断某个规则的开闭状态，在一天的几点到几点间启用，且还可以额外设置是周一到周日的哪几天启用。</p>
<p>于是我看到当时的同事，写一个方法 <code>isSuppressTime</code> ，会给两个参数，第一个参数为一个时间戳 <code>timestamp</code> ，第二个参数为一个 <code>List[Map[String, String]]</code> 。</p>
<p><code>Map[String, String]</code> 里面有4个值，分别是：</p>
<ol>
<li>startTime，从零点到某个具体开始时间的秒数，0~86399。</li>
<li>endTime，从零点到某个具体结束时间的秒数，0~86399。</li>
<li>isDaily，当时间戳在 startTime endTime 之间时，如果此项为 true，则返回 true。</li>
<li>weekdays，周一到周日，1~7，以<code>,</code>间隔组成的字符串，如<code>1,4,5</code>。表示周一、周四、周五且时间戳在 startTime endTime 之间时返回 true</li>
</ol>
<p>最后他写出了如下的代码（Scala）：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isSuppressTime</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> System</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.currentTimeMillis(),</span></span>
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">                   suppressTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> rule.getSuppressTime)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(suppressTimes </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> false</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  import</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> scala</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">collection</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">JavaConversions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">_</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  suppressTimes.foreach(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.size </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> startTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;startTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> endTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;endTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> isDaily</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;isDaily&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekdays</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;weekday&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).split(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;,&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toList</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> zero</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zeroTimestamp()</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">      //今天零点零分零秒的毫秒数</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> start</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> startTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> end</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> endTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (start </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> end </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (isDaily.toBoolean)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> cal</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.getInstance()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">        cal.setTimeInMillis(now)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        var</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> day</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> cal.get(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">DAY_OF_WEEK</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">          day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 7</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        else</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">          day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekday</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day.toString</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (weekdays.contains(weekday))</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  })</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> false</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">private</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> zeroTimestamp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> cal</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.getInstance()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  cal.set(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">HOUR_OF_DAY</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  cal.set(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">SECOND</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  cal.set(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">MINUTE</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  cal.set(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">MILLISECOND</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  cal.getTimeInMillis()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>这个代码看着很长，判断很多，而且还用了超级多陈旧的 API，使得它的性能也不好。而且这是一段 Scala 的代码，却用了较多的 <code>return</code> 和 <code>var</code> ，这两个都是 Scala 不提倡的。最关键的，明明是函数式的代码，他却写出了过程式的感觉。给后面的维护人员（我）带来了不少困扰。</p>
<p>下面，我们来一点点优化这段代码（需要一点点 Java 功底），首先对于方法 <code>zeroTimestamp()</code> ，我第一眼看到的时候，是惊讶的，原作者用了一个比较旧的 <code>Calendar</code> 。对它最深刻的印象就是当年写 <code>SimpleDataFormat</code> 的时候，因为 <code>Calendar</code> 这货导致线程不安全。而每次创建 <code>SimpleDataFormat</code> 的开销比较大，最后不得不写了个 <code>ThreadLocal&lt;simpledataformat&gt;</code> 。</p>
<p>而Java8以后，我们可以直接用 <code>java.time</code> 下面的类来改写 <code>zeroTimestamp()</code> ，这里只需要一行代码，如下：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">private</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> zeroTimestamp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  Timestamp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.valueOf(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LocalDate</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.now().atStartOfDay()).getTime</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>回到 <code>isSuppressTime</code> 方法上来，我姑且不说他的设计多么麻烦，因为这是一个已经被广泛使用的方法，我能做到的就是在不改变签名的情况写来优化实现。</p>
<p>首先，开头我们就看到</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(suppressTimes </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> false</span></span></code></pre>
<p>这个空的判断和强制 <code>return</code> ，在 Java 里面， <code>null</code> 是一个很痛苦的事情，Scala 因为基于 JVM 也不例外，但是 Scala 和 Java 8 都分别有一个 <code>Option</code> 类（Java8是 <code>Optional</code> ），来做空值处理。</p>
<p>所以，我们这里第一时间可以干掉这个判断，写成如下方式</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Option</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]]](suppressTimes).map(times </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">  // ba la ba la</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}).getOrElse(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span></code></pre>
<p>代码里面的 <code>times</code> 为方法中非空的 <code>suppressTimes</code> ，注释部分为核心的处理逻辑，这样我们避免了一个 <code>if</code> 判断，减少了一个 <code>return</code> 。</p>
<p>而其实， <code>Option([A]).map([B] =&gt; Boolean).getOrElse(false)</code> 等价于 <code>Option</code> 的 <code>exists</code> 方法，最后完整的代码应该如下：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isSuppressTime</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> System</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.currentTimeMillis(),</span></span>
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">        suppressTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]])</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  Option</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]]](suppressTimes).exists(times </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    times.foreach(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.size </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> startTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;startTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> endTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;endTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> isDaily</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;isDaily&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekdays</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;weekday&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).split(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;,&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toList</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> zero</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zeroTimestamp()</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">        //今天零点零分零秒的毫秒数</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> start</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> startTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> end</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> endTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (start </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> end </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (isDaily.toBoolean)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">            return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> cal</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.getInstance()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">          cal.setTimeInMillis(now)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          var</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> day</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> cal.get(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">DAY_OF_WEEK</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">            day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 7</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          else</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">            day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekday</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day.toString</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (weekdays.contains(weekday))</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">            return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">        }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    })</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">    false</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  })</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>在上面的例子里面，我们已经干掉了两个 <code>return</code> 和一个 <code>if</code> ，让它有一点 Functional 的感觉了。</p>
<p>上面重构后代码中， <code>times</code> 的类型是 <code>util.List[util.Map[String, String]]</code> 。 <code>times.foreach(params =&gt; {})</code> 里的 <code>params</code> 对应的是 <code>util.Map[String, String]</code> 类型。所以，我们看到判断 <code>if (params != null &amp;&amp; params.size &gt; 0)</code> 时应该会发现，这就是一个list filter的过程嘛。 <code>.filter()</code> 之后不就是一个 <code>.map()</code> ，于是我们可以这么改：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Option</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]]](suppressTimes).exists(times </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  times.filter(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">params.isEmpty).map(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    // ba la ba la</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  }).contains(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">})</span></span></code></pre>
<p>当然 <code>.map(xxx =&gt; Boolean).contains(true)</code> 等价于 <code>.exists()</code> ，于是我们重构的方法如下：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isSuppressTime</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> System</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.currentTimeMillis(),</span></span>
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">        suppressTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]])</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  Option</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]]](suppressTimes).exists(times </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    times.filter(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">params.isEmpty).exists(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> startTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;startTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> endTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;endTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> isDaily</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;isDaily&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekdays</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;weekday&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).split(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;,&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toList</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> zero</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zeroTimestamp()</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">      //今天零点零分零秒的毫秒数</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> start</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> startTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> end</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> endTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (start </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> end </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (isDaily.toBoolean)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> cal</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.getInstance()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">        cal.setTimeInMillis(now)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        var</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> day</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> cal.get(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">DAY_OF_WEEK</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">          day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 7</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        else</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">          day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekday</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day.toString</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (weekdays.contains(weekday))</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">          return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      }</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">      false</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    })</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  })</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>这次重构，我们又去掉了一层 if 判断，改为 filter 实现，减少了一次返回。到了这一步，我们会发现，下面需要实现的就是一个方法，对 <code>util.Map[String, String]</code> 去做处理，返回一个布尔值，于是我们精简方法的实现代码为两部分：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isSuppressTime</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> System</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.currentTimeMillis(),</span></span>
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">                   suppressTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> rule.getSuppressTime)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  Option</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]]](suppressTimes)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    .exists(times </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> times.filter(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">params.isEmpty).exists(isValidateTimes(_, now)))</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>这个为边界过滤的方法。</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">private</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isValidateTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">params</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">], </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> startTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;startTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> endTime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;endTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> isDaily</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;isDaily&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekdays</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;weekday&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).split(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;,&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toList</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> zero</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zeroTimestamp()</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">  //今天零点零分零秒的毫秒数</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> start</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> startTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> end</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> endTime.toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (start </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> end </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (isDaily.toBoolean)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> cal</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.getInstance()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    cal.setTimeInMillis(now)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    var</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> day</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> cal.get(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Calendar</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">DAY_OF_WEEK</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 7</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    else</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekday</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> day.toString</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (weekdays.contains(weekday))</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">      return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  }</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">  false</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>这个为我们要重构的核心处理逻辑。我们优化整理它的判断条件，最后可以实现如下的完整代码：</p>
<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" icon="&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z&quot; fill=&quot;currentColor&quot; /&gt;&lt;/svg&gt;"><code class="language-scala"><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isSuppressTime</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> System</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.currentTimeMillis(),</span></span>
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">                   suppressTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> rule.getSuppressTime)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  Option</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">List</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]]](suppressTimes)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    .exists(times </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> times.filter(params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">params.isEmpty)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    .exists(isValidateTimes(_, now)))</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">private</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> isValidateTimes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">params</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: java.util.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">], </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">now</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Long</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Boolean</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> zero</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zeroTimestamp()</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> start</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;startTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> end</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> zero </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;endTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toLong </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1000</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> isDaily</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;isDaily&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toBoolean</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekdays</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> params.get(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;weekday&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).split(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">&quot;,&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).toList</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  val</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weekday</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> LocalDate</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">.now().getDayOfWeek.getValue.toString</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  (start </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> end </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&gt;=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> now)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (isDaily </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> weekdays.contains(weekday))</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
<p>这样，我们就实现了一个 <code>if</code> 都没有，一个 <code>return</code> 都没有的纯函数式写法。</p>
<p>总的来说，代码谁都能写出来，但是把需求从文字或者是流程描述换成编码实现时就有了对程序员抽象逻辑能力的需求。如何组织抽象，就像是如何写作文，或者是 Kata（空手道里面的招数、套路），不要按照业务描述写 if else，而要尽可能简化找到一致性的简单逻辑描述。</p>
<p>如果能将所有的特殊情况变为通用情况，简化逻辑判断，那么代码在后面的迭代中也会比较易于维护。</p>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/encoding">编码</category>
            <category domain="https://stage.yufan.me/tags/programming">编程</category>
            <category domain="https://stage.yufan.me/cats/coding">编程</category>
            <enclosure url="https://stage.yufan.me/images/og/rewrite-your-logic.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[哲学与思考]]></title>
            <link>https://stage.yufan.me/posts/philosophy-and-thinking</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/philosophy-and-thinking</guid>
            <pubDate>Thu, 28 Jun 2012 10:55:39 GMT</pubDate>
            <description><![CDATA[有句话说得好，哲学，出自一群无聊的闲人手里。苏格拉底的妻子苏珊娜就曾经如此自白：“我是苏格拉底的妻子苏珊娜，我的丈夫苏格拉底是一个著名的懒汉。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2012/06/2012062823295700.jpg"/><link rel="preload" as="image" href="https://cat.yufan.me/images/2012/06/2012062823300200.jpg"/><img src="https://cat.yufan.me/images/2012/06/2012062823295700.jpg" alt="空の研究 - 杉87"/>
<div class="mt-5 mb-5.5 max-w-87.5 max-xl:mx-auto max-md:mx-0 max-md:mt-0 max-md:mb-5 max-md:max-w-full"><div class="aplayer" data-id="gqtlakzpavvor2rc"></div></div>
<p>有句话说得好，哲学，出自一群无聊的闲人手里。苏格拉底的妻子苏珊娜就曾经如此自白：“我是苏格拉底的妻子苏珊娜，我的丈夫苏格拉底是一个著名的懒汉。他每天一大早就起床，吃完早饭就出门了，他没有工作，我也不知道他每天都在外面做些什么。家里的日子很贫寒，总是无米下锅，我很为家里的生计着急，觉得不能每次都靠柏拉图他们来接济，咱们家应该自食其力，于是每次都劝他找份工作，干个家教什么的，但是他从来都把我的话当耳边风。”</p>
<p>同样地，马克思也是有名的闲散之士，成天就靠着恩格斯的接济过活。而想想原因，也并非没有道理。大学教授问他的学生一天都干了些什么，学生列出满满一张日程表，最后教授惊呼“天哪，那你哪有时间思考呀？！”</p>
<p>思考需要时间，这是显而易见的，但却又那么容易被人忽视。每天过着忙碌敲代码的生活，哪里有时间思考。强迫自己写一篇日志之类的东西，其实也是强迫自己抽出一些时间去思考。生活的忙碌，就像小沈阳说的，“一睁眼一闭眼，一天就过去了”。</p>
<p>时间就像流沙一样从指缝流逝着，而自己却似乎什么都还没有做成。</p>
<p style="text-align:center">~ fin ~</p>
<img src="https://cat.yufan.me/images/2012/06/2012062823300200.jpg" alt="清涼の夏 - 杉87"/>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/philosophy">哲学</category>
            <category domain="https://stage.yufan.me/cats/think">杂思</category>
            <enclosure url="https://stage.yufan.me/images/og/philosophy-and-thinking.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[夜の思考]]></title>
            <link>https://stage.yufan.me/posts/nocturne</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/nocturne</guid>
            <pubDate>Sat, 09 Jun 2012 19:46:08 GMT</pubDate>
            <description><![CDATA[不知从何时起，我爱上了那深藏不露的黑色。只因为夜。每至深夜时，我总是习惯性地关上灯，静静地立在窗前，任凭月光如瀑般倾泻全身，以及随之而来的纷涌思绪。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2012/06/2012061019294700.jpg"/><link rel="preload" as="image" href="https://cat.yufan.me/images/2012/06/2012061019294200.jpg"/><img src="https://cat.yufan.me/images/2012/06/2012061019294700.jpg" alt="Alca - あの日の答え"/>
<div class="mt-5 mb-5.5 max-w-87.5 max-xl:mx-auto max-md:mx-0 max-md:mt-0 max-md:mb-5 max-md:max-w-full"><div class="aplayer" data-id="1hvrb3y1g3ovurqn"></div></div>
<p>不知从何时起，我爱上了那深藏不露的黑色。</p>
<p>只因为夜。</p>
<p>每至深夜时，我总是习惯性地关上灯，静静地立在窗前，任凭月光如瀑般倾泻全身，以及随之而来的纷涌思绪。</p>
<p>也许，只有当俗世的一切喧嚣与繁华沉寂在这无边的夜时，我们才得以摘下白天的面具，让自己的灵魂在月光的抚慰下得到一丝安宁。或许，也只有此时，我们才能够真正地看清自我。</p>
<p>静默的黑夜是思想者的天堂。夜深人静之时，我们的心才得以自由地舞动于风中，在夜神的陪伴下细细地品味人生百态。</p>
<p>一向不喜在夜里喝咖啡，相反，我更情愿在这令人沉醉的黑夜中倒上一盏香茗。咖啡的味道太浓、太重，是只属于那些都市人的佳酿。而茶，却是淡淡一缕幽香。</p>
<p>茶香完美地与夜融为一体。人生，有时也如茶一样，淡然无味，甚至微微作苦。惟有在喝下去之后，才能体味到，那残留于舌根的一缕清香。</p>
<p>在夜晚听音乐亦不失为一种享受。闭上眼，听着那曼妙的旋律飘荡于月光中，只感到自己的呼吸已同时间一起消逝于无尽的黑暗中……</p>
<p>每一次在夜中，我都能获得不同的启示。有时，耳边仿若飘荡着来自古希腊吟游诗人的声音，一个个古老而又神秘的音符中，传颂着无数掩埋于历史尘埃之中的故事。关于爱情与热血、生命与信念……</p>
<p>夜，永远是最神秘莫测的精灵之一。它似乎无所不知，能够洞察每一个人的灵魂，却又如海般包容一切，所有的美与丑、善与恶，都被笼罩于黑暗之中。它总在你不经意间悄悄降临，当你回过神时，又早已离去。它像一只翱翔的鹰，孤傲地振翅于云霄之上，漠然地注视着人间的一切却又从不为之停留，只在地面上投下它巨大的身影。</p>
<blockquote>
<p>轻轻的<br/>
<!-- -->放缓呼吸<br/>
<!-- -->让心带着你的全部<br/>
<!-- -->一同溶解在似水的黑暗之中<br/>
<!-- -->只余下夜……</p>
</blockquote>
<img src="https://cat.yufan.me/images/2012/06/2012061019294200.jpg" alt="Alca - 色鮮やかな記憶"/>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/night">夜</category>
            <category domain="https://stage.yufan.me/tags/reprint">转载</category>
            <category domain="https://stage.yufan.me/cats/article">文章</category>
            <enclosure url="https://stage.yufan.me/images/og/nocturne.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[19岁的“雨季”]]></title>
            <link>https://stage.yufan.me/posts/19-year-old</link>
            <guid isPermaLink="false">https://stage.yufan.me/posts/19-year-old</guid>
            <pubDate>Sat, 09 Jul 2011 05:01:20 GMT</pubDate>
            <description><![CDATA[这样的雨，实在是让人烦恼，接连数日，没有停的时候。这样的雨里，想做的事情实在很少。天空灰蒙蒙的，心情也仿佛蒙了灰尘，让人感觉整个世界变得忧郁而烦闷。]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://cat.yufan.me/images/2019/05/2019051819372187.jpg"/><link rel="preload" as="image" href="https://cat.yufan.me/images/2019/05/2019051819371735.jpg"/><img src="https://cat.yufan.me/images/2019/05/2019051819372187.jpg" alt="雨宿り by  ハトリ"/>
<div class="mt-5 mb-5.5 max-w-87.5 max-xl:mx-auto max-md:mx-0 max-md:mt-0 max-md:mb-5 max-md:max-w-full"><div class="aplayer" data-id="lrxyj630rt4wsz31"></div></div>
<p>这样的雨，实在是让人烦恼，接连数日，没有停的时候。</p>
<p>这样的雨里，想做的事情实在很少。天空灰蒙蒙的，心情也仿佛蒙了灰尘，让人感觉整个世界变得忧郁而烦闷。</p>
<p>对于雨天，从小就是心怀不平的。</p>
<p>只那么一夜，树叶洒落一地，不由得惊叹秋雨竟如此冰冷无情，想起曾经读过的许多雨天的文章，总是不了解作家的心境，不了解他们怎么会有那样美妙、美好的感觉，自己始终无法体味。</p>
<p>就在深秋的一个黄昏，那拍落了叶的街头树与自己相对而立，默默无语地看着一如既往的街景和匆匆的行人，偶尔有一片叶悠悠落下，就这样悄然而立，接受暮里落叶飘零的情意。</p>
<p>难道花季来过，雨季已悄然来临？</p>
<p>花季……风和日丽的港湾……</p>
<p>虽然是在措手不及间踏上这样一条未知的路，虽然花季初至也曾经彷徨，但永远无法忘却的是美丽的心情；永远不放弃的是成长的意义，没有任何感伤，只有如期而至的平静与欣慰。</p>
<p>没有显赫的身世，没有令人瞩目的才能，却很早就学会用神的笔画着：“我爱祖国”……</p>
<p>没有英俊的外表，没有名牌的衣裳，但这并不重要，阳光、闲适不就是一种自然舒适的心情？</p>
<p>没有人注意自己，也不期待有人为自己鼓掌。毕竟花季不是一路鲜花，一路喝彩……</p>
<p>因为花季中也有无数飘雨的日子……</p>
<p>常常被一些真挚的情意感动而流泪，是在花季里呢？</p>
<p>喜欢在黑夜里孤灯下遥望繁星，聆听“吱吱”的昆虫声，是在花季里呢？</p>
<p>那些被伤害的日子里，学会去思考，去面对，去品悟，是在花季里吧？</p>
<p>我的花季，不是浪漫的粉红色。</p>
<p>以为 19 岁时开满鲜花的，19 岁的字典里也没有“忧伤”这个词，但走进花季，才明白自己和别人不同，也没有资格拥有他们拥有的一切欢笑，自己保留的是一种真诚，不断地使自己完整，不断地寻求自知，体验生活自己拥有的，也只是心底纯净的蔚蓝色的天空。</p>
<p>那一切缤纷的往日在脑中一遍遍重复，像一部黑白的老电影，亲切至极而依然毫无厌倦，是不是他也曾注意，那时的许多美丽的黄昏？</p>
<p>花季是一条路，注定每人都要走过，都要面对，站在这个路口，会想起失败和失败者，想起跋涉和跋涉者……但别无选择，我们属于这条路。</p>
<p>总是想起年少时有过的许多幻想，都在岁月积累的颠簸中碰撞坍塌了，伤心、感慨，昔时难再的悲伤，但谁不是这样？谁的心不是在这样的坎坷中成长起来的，庆幸的是有失去就有得到，就在这些磨难之后，才会进入一种境界，才会拥有一种面对现实的决心，一种明了生命的镇定，就算付出了生命中最宝贵的年华，也无需太在意，不是么？我们所追求的一切，在自己看来却是美丽令人心悸，但最终要得到它还要经过岁月的洗礼，这难道不是一种无可奈何的安排吗？</p>
<p>那么，就让自己忘记得与失。</p>
<p>走了，花季终于永远地走了，而自己永远也无法再抓住那纯好梦幻时光，可是，如果在走出花季后，能得到一种原本无法认知的感悟，那么又何不笑着面对命运呢？</p>
<p>让自己向花季道别吧！如果心真的已不再年轻，再也想不起回忆，那么，就像花季道别吧。</p>
<p>如果走出花季以后，每一件伤心的往事都能让自己深深地醒悟，每一次感悟都能让自己成长许多，每一次成长都能让自己正视过去与现在，每一次回顾中，每个有雨的日子，都能在心底抽出一张浅浅淡淡的风景……那么走出花季又有什么不好呢？</p>
<p>于是，就在雨季中道别花季……</p>
<p>然而，夕阳里，风景依旧迷人。</p>
<img src="https://cat.yufan.me/images/2019/05/2019051819371735.jpg" alt="雨宿り by  おかだアンミツ"/>]]></content:encoded>
            <author>syhily@gmail.com (雨帆)</author>
            <category domain="https://stage.yufan.me/tags/flower-season">花季</category>
            <category domain="https://stage.yufan.me/tags/rainy-season">雨季</category>
            <category domain="https://stage.yufan.me/tags/adolescence">青春期</category>
            <category domain="https://stage.yufan.me/tags/irritability">烦躁</category>
            <category domain="https://stage.yufan.me/tags/thinking">思考</category>
            <category domain="https://stage.yufan.me/tags/farewell">告别</category>
            <category domain="https://stage.yufan.me/cats/article">文章</category>
            <enclosure url="https://stage.yufan.me/images/og/19-year-old.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>