やりたいこと
PHPだと、以下のように連想配列を利用できます。
<?php
$array = array();
$array["a"]["sub-1"] = 111;
$array["a"]["sub-2"] = 222;
$array["b"]["sub-1"] = 333;
print_r($array);
実行結果は、
Array
(
[a] => Array
(
[sub-1] => 111
[sub-2] => 222
)
[b] => Array
(
[sub-1] => 333
)
)
一目瞭然ですね。素敵です。
こんな感じでサクサク連想配列をGroovyでも使いたいですね。
Groovyだと連想配列に該当するのはMapになります。
実際にやってみましょう。
def map = [:] // Mapインスタンスの生成
map ["a"]["sub-1"] = 111
しかし、コレを実行するとjava.lang.NullPointerException: Cannot set property 'sub-1' on null object
という例外が発生します。
というのも、GroovyのMapの動作として、まずmap["a"]
から値を取得して、その値のsub-1
というプロパティに111を代入する、という流れになっているので、そもそもmap["a"]
は何もないのでnullを返すため、nullのプロパティに値を突っ込もうとしてもダメだよ!と怒られているんですね。
assert map["a"] == null
解決方法
GroovyのMapには、「該当するキーがなければ、そのキーと指定したデフォルト値を使って新しい値をMapに突っ込む」という便利メソッドwithDefault
があります。
鋭い人ならこの時点でピンと来るかもしれません。このwithDefaultを使って、キーが存在しない場合には、そのキーをキーとして 新しいMap を突っ込んであげれば上記の問題を解決できます。
日本語だけだと何がなんだかわからないですね。実際のソースを見てみれば一目瞭然です。
def map = [:].withDefault{[:]}
map["a"]["sub-1"] = 111
map["a"]["sub-2"] = 222
map["b"]["sub-1"] = 333
assert [
"a":[
"sub-1":111,
"sub-2":222
],
"b":[
"sub-1":333
]
] == map
最初の[:]
でMapインスタンスを生成するタイミングで、.withDefault{[:]}
を使って、キーが存在しない場合には空の新しいMapを返すように宣言しています。
これで、GroovyでもPHPの連想配列のように、よりお気楽にMapが利用できるようになります。