亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

代碼里的詩情畫意

写代码就像写诗一样。

照片由 Christiaan Huynen 拍摄,来自 Unsplash 平台

你有没有听说过开发者说过他们的代码就像诗歌一样?我们在写代码时有时会非常珍爱它。当开发者说“代码像诗歌一样”时,他们的意思是代码读起来流畅,结构良好。我们可能会声称我们的代码优雅且非常易读。这些评判标准是主观的,并不是所有人都认同,尤其是对于他们来说不熟悉的时候。我认为大多数代码应该像儿童读物一样。代码应当清晰地告诉你它的含义和作用,不需要过多的解密或调查。代码应该像一篇简短的非虚构故事。我见过太多代码像悬疑或科幻小说一样复杂。保持简单!

有一种方法可以让我们的代码看起来像诗歌一样优美。我们可以在代码中嵌入真正的诗歌内容。我建议你使用自己拥有版权或有使用许可的诗歌。

供Java文本块编写的诗歌

Java 在 Java 14 中新增了一个很酷的功能叫做文本块。我见过的大多数代码示例都使用文本块来编写 SQL 语句等文本。我发现用 Java 文本块写诗非常有趣。这里有一个我在高中时写的名为“玩沙子”的诗的例子,用 Java 文本块存放在一个静态变量中。

    private static final String PLAYING_IN_THE_SAND =  
            """  
            戏沙  

            能否真正了解  
                一粒沙的美丽?  
            在漫不经心中抛掷  
                被某人筛过;  
            它们被冲上我们的海滩  
                随潮水来回;  
            社会的镜子般  
                映出我们隐藏的思想。  
            总是感受到但从未被看见  
                像被遗留下的东西;  
            没有人关心个人,  
                砂粒却似乎并不在意。  
            它们是海滩的晶体  
                却如同棋盘上的棋子;  
            我们只是把它们从毛巾上抖落  
                从衣服上拂去。  
            孩子们盒子里的国王  
                却如同棋盘上的棋子;  
            我们应该问自己这个问题,  
                如果它们消失,我们会想念吗?  
            """;

这首诗以Java文本块的形式呈现,非常易于阅读。我可以按照我最初创作这首诗时所设想的格式来呈现,这已经是三十多年前的事了。希望你会喜欢这首诗。几年前我写了一篇博客,里面包含了这首诗以及一些背景信息。

一首关于玩沙子的诗(Playing in the Sand)

令人惊讶的是,我在Java里用文本块格式化代码比在Medium上格式化诗歌还简单。我不得不粘贴一些图像以保留我原本打算的格式,这些格式能给读者提供关于诗歌节奏的提示。

如果使用 Java 14 之前要求的经典字符串拼接风格来写这首诗,可读性会大大降低。这里是用 Java 经典 String 字面表示的同一首。

        private static final String PLAYING_IN_THE_SAND =  
                "玩沙\n" +  
                "\n" +  
                "谁能真正领略\n" +  
                "    粒粒细沙之美?\n" +  
                "被轻率地抛洒\n" +  
                "    或是有人轻筛。\n" +  
                "它们被冲上沙滩\n" +  
                "    随着潮水再回;\n" +  
                "社会的镜像\n" +  
                "    映出我们隐藏的想法。\n" +  
                "常常被感受却从不被看见\n" +  
                "    像是被遗忘的痕迹;\n" +  
                "对于每个人无人在意,\n" +  
                "    然而细沙却无怨无悔。\n" +  
                "它们是沙滩上的晶体\n" +  
                "    却被视作尘埃;\n" +  
                "我们只是轻轻拂去\n" +  
                "    毯子上的沙,或是衬衫上的尘。\n" +  
                "孩子们玩具箱中的宝藏\n" +  
                "    在我们眼中却如同弃卒;\n" +  
                "我们应该自问,\n" +  
                "    如果它们消失,我们会怀念吗?\n";

虽然我们可以阅读这段文字,但我们很容易被引号、换行符和加号分散注意力,从而失去专注。Java 文本块是 Java 语言在编码时一个很好的例子,它不会碍事,进行编码时。

编码诗歌的快乐

编程很有趣。用诗意的方式编程也同样有趣。至少对我来说是这样。代码和诗歌既要有意思给作者,也要有意思给读者。希望你在接下来的例子中,既能欣赏代码,也能感受到诗歌的魅力。

我在测试里用“Playing in the Sand”这首诗编写了一些有趣的代码片段。希望你玩得开心!

找到所有单词

首先,我们可以找出诗中的所有单词并将它们存入 Bag 中。BagEclipse Collections 中的一种 Collection 类型,它可以追踪项目及其数量。这种数据结构能立即让我们数清单词的数量。

    private static final ImmutableBag<String> 混合大小写单词集合 =  
            StringIterate.injectIntoTokens(  
                            PlayingInTheSand,  
                            " ,.-!;?\t\n\r\f",  
                            Bags.mutable.<String>empty(),  
                            MutableBag::with)  
                    .toImmutable();

利用 Eclipse Collections 中的 StringIterate 工具类,我们可以快速通过 injectIntoTokens() 方法创建一个 MutableBag<String> 对象。接着,通过调用 toImmutable() 方法将 MutableBag<String> 转换为不可变的 ImmutableBag<String> 对象。

将所有单词都转成小写

我们将所有包含大小写混合的单词转换成小写,比如使用 collect() 方法和一个 Function 来转换。

    private static final 不可变袋<String> 小写单词 = 
            混合大小写单词.collect(字符串::toLowerCase);
看来看这诗的解析

现在我们已经将这首诗编码成了 Java 文本块,并将大小写混合和全小写的单词解析为单独的 ImmutableBag<String> 实例,我们可以编写一些 JUnit 5 单元测试来了解更多关于这首诗的信息。我们将使用 Eclipse Collections 支持的所有 RichIterable 类型都理解的方法,例如 sizeselectrejecttoSet 等。我们还将使用特定于 Bag 类型的方法,例如 selectDuplicatesselectUniquetopOccurrences 等。

数单词

我们首先可以计算总词数,确认期望的词数是118个词,从而验证injectIntoTokens()函数是否正确。

    @Test  
    public void 单词计数()  
    {  
        Assertions.assertEquals(118, this.getLowerCaseWords().size());  
    }
找到Wordle里的单词

大家可能还记得几年前风靡一时的Wordle热潮。我们可以用下面的代码来找出可能成为Wordle单词的词。

    @Test  // 测试方法wordleWords
    public void wordleWords()  // 定义测试方法wordleWords
    {  
        Bag<String> words = this.getLowerCaseWords();  // 获取所有小写单词,并存入Bag中
        Set<String> wordleWords = words.asLazy()  // 将Bag转换为惰性集合
                .rejectWith(String::contains, "'")  // 过滤包含单引号的单词
                .select(word -> word.length() == 5)  // 选择长度为5的单词
                .toSet();  // 将选择结果转为Set
        ImmutableSet<String> expected =  // 定义期望的单词集
                Sets.immutable.with(  // 使用ImmutableSet定义期望的单词列表
                        "cares", "never", "would", "shake",  
                        "boxes", "grain", "about", "glass",  
                        "still", "kings", "brush", "pawns");  // 列出期望单词
        Assertions.assertEquals(expected, wordleWords);  // 验证实际结果与期望结果是否一致
    }

我们通过调用 asLazy()Bag<String> 转换为 LazyIterable<String>。我们使用 rejectWith 来排除任何缩略词,因为它们不是有效的 Wordle 单词。然后我们使用 select 来筛选出所有包含长度为五的单词。最后,我们将返回的 LazyIterable<String> 转换为 MutableSet<String>MutableSet<String> 扩展了 Set<String>

找到那些开头字母是大写的单词

下面的代码将找到首字母大写的单词,这些单词位于ImmutableBag<String>中。

    @Test  
    public void 首字母大写单词()  
    {  
        Set<String> firstUpperCaseWords = this.get混合大小写单词()  
                .select(each -> Character.isUpperCase(each.charAt(0)))  
                .toSet();  

        Set<String> expected =  
                Set.of("The", "Can", "Sand", "We", "Always", "For",  
                        "Playing", "Tossed", "They're");  

        Assertions.assertEquals(expected, firstUpperCaseWords);  
    }

我们使用 select() 方法来筛选首字母大写的单词。这样会返回一个 Bag<String>,因为我们是从 getMixedCaseWords() 返回的 Bag<String> 调用 select() 方法。如果我们将 getMixedCaseWords() 的返回类型改为 ImmutableBag<String>,那么 select() 会返回一个 ImmutableBag<String>

找重复单词

以下代码将找到重复出现的单词。我们断言从 selectDuplicates() 方法调用返回的 Bag<String> 中单词的数量应与单元测试中的预期结果 Bag<String> 相匹配。

@Test  
public void 重复的单词()  
{  
    Bag<String> words = this.获取小写单词();  

    Bag<String> duplicateWords =  
            words.选择重复的();  

    Bag<String> expected =  
            可变字符串袋.mutable  
                    .包含出现次数("in", 2)  
                    .包含出现次数("sand", 2)  
                    .包含出现次数("to", 2)  
                    .包含出现次数("but", 2)  
                    .包含出现次数("beaches", 2)  
                    .包含出现次数("so", 2)  
                    .包含出现次数("the", 10)  
                    .包含出现次数("like", 2)  
                    .包含出现次数("and", 3)  
                    .包含出现次数("of", 5)  
                    .包含出现次数("them", 3)  
                    .包含出现次数("off", 2)  
                    .包含出现次数("they're", 2)  
                    .包含出现次数("our", 4)  
                    .包含出现次数("we", 4);  
    断言.assertEquals(expected, duplicateWords);  
}
查找独特词汇

以下代码将找到唯一出现的单词。我们将 selectUnique() 方法的结果与预期的 Set<String> 进行比较。调用 selectUnique() 时,该方法返回一个 RichIterable(丰富的可迭代对象)

    @Test  
    public void uniqueWords()  
    {  
        Bag<String> words = this.getLowerCaseWords();  

        RichIterable<String> uniqueWords =  
                words.selectUnique();  

        Set<String> expected =  
                Set.of("nobody", "they", "individual", "shake",  
                        "by", "pawns", "sent", "were", "hide",  
                        "would", "shirts", "on", "something", "dirt",  
                        "thoughts", "sifted", "behind", "carelessness",  
                        "gone", "much", "many", "washed", "children's",  
                        "brush", "ask", "towels", "this", "ever",  
                        "simple", "one", "about", "kings", "beauty",  
                        "looking", "hand", "someone's", "can", "tide",  
                        "glass", "for", "left", "treated", "mind",  
                        "question", "tossed", "just", "with", "ourselves",  
                        "society", "a", "boxes", "don't", "back",  
                        "always", "us", "still", "seen", "seem", "should",  
                        "playing", "know", "reflecting",  
                        "up", "cares",  
                        "crystals", "never", "felt", "grains", "grain",  
                        "miss", "yet");  

        Assertions.assertEquals(expected, uniqueWords);  
    }
找出最常用的三个词

我最喜欢 Bag 的一个方法是 topOccurrences()。这个方法很酷,能做很多事情。我们传入一个整数来指定需要返回的顶级出现次数。然后它会返回一个 List,包含每个项目及其总出现次数的键值对。

    @Test  
    public void 获取Top三个单词()  
    {  
        Bag<String> words = this.getLowerCaseWords();  

        ObjectIntPair<String> 列表迭代器 topThreeWords =  
                words.topOccurrences(3);  

        List<ObjectIntPair<String>> expected = List.of(  
                原始元组对("the", 10),  
                原始元组对("of", 5),  
                原始元组对("we", 4),  
                原始元组对("our", 4)  
        );  
        断言.断言等于(expected, topThreeWords);  
    }

首先,代码中应该立即引起注意的是,我们说想要前三个单词,但实际上得到了四个。这是topOccurrences()方法的一部分规定。如果出现并列情况,可能会返回更多的结果,因此调用此方法的开发人员需要决定如何处理并列情况。在这里可以看到,“我们”和“我们的”在诗中都出现了四次。

最终的想法

我希望你喜欢这些代码示例和诗,以及我在示例中使用的那首诗。使用Bag类型解析文本并计算单词数量是一个简单而有趣的例子,应该易于阅读和理解。分析Bag中的结果也很有趣,因为Bag类型提供给我们回答关于它维持的“计数”的具体问题的有用方法。

Java 最近新增的文本区块功能让这样的代码示例更有趣且更容易阅读。

谢谢您的阅读!

我创建并维护_ Eclipse Collections 这个开源项目,该项目托管于 Eclipse基金会 。Eclipse Collections接受贡献,请参阅 CONTRIBUTING.md_。

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消