Java和Groovy中的映射映射很通用,允许关键字key和value值是任意类型,只要继承Object类即可。我最近在探索Java和Groovy在创建和初始化列表以及在运行时构建列表方面的一些差异。我观察到,在实现这些特性时,Groovy的简单性与Java的复杂性形成鲜明对比。在本文中,我将使用Java和Groovy实现创建和初始化地图。地图提供了开发支持按键检索的结构的可能性,如果找到这样的键,它会返回相应的值。今天,许多编程语言都实现了映射,包括Java和Groovy,还有Python(将映射称为字典dict)、Perl、awk等等。另一个常用于描述映射的术语是关联数组,您可以在这篇维基百科文章中阅读更多相关信息。Java和Groovy中的映射都非常通用,允许关键字和值是任何类型,只要它们继承自Object类即可。安装Java和GroovyGroovy是基于Java的,所以需要先安装Java。您的Linux发行版的存储库中可能有最新的Java和Groovy版本。或者,您也可以按照上面链接中的说明安装Groovy。对于Linux用户,SDKMan是一个很好的选择,您可以使用它来获得多个Java和Groovy版本,以及许多其他相关工具。在本文中,我使用的SDK发行版是:Java:OpenJDK11的版本11.0.12-open;Groovy:版本3.0.8。言归正传Java提供了很多实例化和初始化地图的方法,并且从Java9之后,又增加了一些新的方法。最明显的方法是使用java.util.Map.of()静态方法,下面是如何使用它:varm1=Map.of("AF","Afghanistan","AX","?landIslands",“AL”、“阿尔巴尼亚”、“DZ”、“阿尔及利亚”、“AS”、“美属萨摩亚”、“AD”、“安道尔”、“AO”、“安哥拉”、“AI”、“安圭拉”、“AQ","南极洲");System.out.println("m1="+m1);System.out.println("m1是一个实例"+m1.getClass());事实证明,在这种情况下,Map.of()有两个重要的限制。首先,以这种方式创建的映射实例是不可变的。其次,最多只能提供20个参数来表示10个键值对。您可以尝试添加第10对和第11对,比如“AG”、“AntiguaandBarbuda”和“AR”、“Argentina”,看看会发生什么。您会发现Java编译器尝试并未能找到支持11个键值对的Map.of()方法。快速浏览java.util.Map类的文档可以揭示上述第二个限制的原因,以及解决这个难题的方法:varm2=Map.ofEntries(Map.entry("AF","Afghanistan"),Map.entry("AX","奥兰群岛"),Map.entry("AL","阿尔巴尼亚"),Map.entry("DZ","阿尔及利亚"),Map.entry("AS","American萨摩亚"),Map.entry("AD","安道尔"),Map.entry("AO","安哥拉"),Map.entry("AI","安圭拉"),Map.entry("AQ","南极洲"),Map.entry("AG","安提瓜和巴布达"),Map.entry("AR","阿根廷"),Map.entry("AM","亚美尼亚"),Map.entry(“AW”,“阿鲁巴”),Map.entry(“AU”,“澳大利亚”),Map.entry(“AT”,“奥地利”),Map.entry(“AZ”,“阿塞拜疆”),地图.entry("BS","Bahamas"),Map.entry("BH","Bahrain"),Map.entry("BD","Bangladesh"),Map.entry("BB","Barbados"));System.out.println("m2="+m2);System.out.println("m2是一个实例"+m2.getClass());这是一个更好的解决方案,前提是我不和你在一起在以下代码中更改使用Map.ofEntries()创建和初始化的地图的内容请注意,我使用Map.ofEntries()而不是上面的Map.of()。但是,假设我想创建并初始化一个非空映射,然后向该映射添加数据,我需要这样做:varm3=newHashMap(Map.ofEntries(Map.entry("AF","阿富汗"),Map.entry("AX","奥兰群岛"),Map.entry("AL","阿尔巴尼亚"),Map.entry("DZ","阿尔及利亚"),Map.entry("AS","美属萨摩亚"),Map.entry("AD","安道尔"),Map.entry("AO","安哥拉"),Map.entry("AI","安圭拉"),Map.entry("AQ","Antarctica"),Map.entry("AG","AntiguaandBarbuda"),Map.entry("AR","Argentina"),Map.entry("AM","亚美尼亚"),Map.entry("AW","阿鲁巴"),Map.entry("AU","澳大利亚"),Map.entry("AT","奥地利"),Map.entry("AZ","阿塞拜疆"),Map.entry("BS","巴哈马"),Map.entry("BH","巴林"),Map.entry("BD","孟加拉国"),Map.entry("BB","Barbados")));System.out.println("m3="+m3);System.out.println("m3是"+m3.getClass());m3.put("BY","白俄罗斯");System.out.println("BY:"+m3.get("BY"));在这里,我使用由Map.ofEntries()创建的不可变映射作为HashMap的构造参数,它创建地图的可变副本,然后我可以对其进行修改——例如使用put()方法让我们看看如何在Groovy中实现上述过程:defm1=["AF":“阿富汗”、“AX”:“奥兰群岛”、“AL”:“阿尔巴尼亚”、“DZ”:“阿尔及利亚”、“AS”:“美属萨摩亚”、“AD”:“安道尔”、“AO”:"Angola","AI":"Anguilla","AQ":"Antarctica","AG":"AntiguaandBarbuda","AR":"Argentina","AM":"Armenia","AW":"Aruba","AU":"澳大利亚","AT":"奥地利","AZ":"阿塞拜疆","BS":"巴哈马","BH":"巴林","BD":"孟加拉国"","BB":"巴巴多斯"]println"m1=$m1"println"m1是${m1.getClass()}的实例"m1["BY"]="白俄罗斯"println"m1=$m1"乍一看,您会发现Groovy使用def关键字而不是var——尽管在最近的后期模型Groovy(版本3+)中也可以使用var关键字。您还会注意到,您通过在括号内添加键值对列表来创建地图。不仅如此,由于多种原因,以这种方式创建的列表对象也非常有用。第一,它是可变的;其次,它是LinkedHashMap的一个实例,内部维护着数据的插入顺序。因此,当您运行代码的Java版本并打印出变量m3时,您将看到:m3={BB=Barbados,BD=Bangladesh,AD=Andorra,AF=Afghanistan,AG=AntiguaandBarbuda,BH=Bahrain,AI=安圭拉,AL=阿尔巴尼亚,AM=亚美尼亚,AO=安哥拉,AQ=南极洲,BS=巴哈马,AR=阿根廷,AS=美属萨摩亚,AT=奥地利,AU=澳大利亚,??DZ=阿尔及利亚,AW=阿鲁巴,AX=?landIslands,AZ=Azerbaijan}当您运行代码的Groovy版本时,您将看到:m1=[AF:Afghanistan,AX:?landIslands,AL:A??lbania,DZ:Algeria,AS:AmericanSamoa,AD:Andorra,AO:Angola,AI:Anguilla,AQ:Antarctica,AG:AntiguaandBarbuda,AR:Argentina,AM:Armenia,AW:Aruba,AU:Australia,AT:Austria,AZ:Azerbaijan,BS:Bahamas,BH:Bahrain,BD:Bangladesh,BB:Barbados]同样,您将看到Groovy如何简化事情。这种语法非常直观,有点像Python中的字典,而且,即使你有一个超过10个键值对的初始列表,你也不需要记住所有必要的笨拙。注意我们使用的表达式:m1["BY"]="Belarus"而在Java中你会这样做:m1.put("BY","Belarus")另外,这张地图默认是可变的,很难判断优劣和这样做的缺点,它仍然取决于您的需求。就个人而言,在这种情况下,Java的“默认不可变”机制最让我困扰的是它没有像Map.mutableOfMutableEntries()这样的方法。这迫使一些刚学会如何声明和初始化映射的程序员不得不考虑如何将手中的不可变映射转换为可变映射。同时我也想问一下,创建一个不可变对象然后丢弃真的好吗?另一件值得考虑的事情是Groovy使用方括号代替Java的put()和get()方法来查找关键字。所以你可以写:m1["ZZ"]=m1["BY"]而不是:m1.put("ZZ",m1.get("BY"))使用键和值是个好主意在地图中作为类的实例变量。假设您有一堆要设置的属性。在Groovy中,它们看起来像这样:defproperties=[verbose:true,debug:false,logging:false]然后,您可以更改其中一个属性,像这样的东西:properties.verbose=false可以工作,因为,只要关键字符合某些规则,您可以省略引号并简单地使用点运算符而不是方括号。虽然这个特性非常有用且易于使用,但这也意味着如果你想使用一个变量作为映射关键字,你必须将变量括在括号中,像这样:defmyMap=[(k1):v1,(k2):v2]是时候告诉勤奋的读者Groovy是一种为脚本编写的语言。地图通常是脚本中的关键元素,为脚本提供查找表并通常充当内存数据库。我在这里使用的示例是ISO3166两个字母的国家代码和国家名称。这些代码为世界各国的互联网用户所熟悉。另外,如果我们想编写一个脚本工具从日志文件中查找Internet主机名并使用它们来了解用户的地理分布,那么这些代码将是非常有用的部分。Groovy相关资源ApacheGroovy网站有大量文档。另一个很棒的Groovy资源是Haki先生。Baeldung网站提供了许多有用的Java和Groovy教程。学习Groovy的另一个重要原因是学习Grails,这是一个出色且高效的全堆栈Web框架。它建立在许多伟大的组件之上,如Hibernate、SpringBoot、Micronaut等。