JavaSE 7でメソッド名に使えなくなった文字
パッケージJava製品開発担当の大です。こんにちは。
朝晩はだいぶ肌寒くなって、秋らしい空気になってきましたね。
前回も書いたとおり、現在HOSでは製品のJavaSE 7での動作検証を進めています。JavaSE 7で早く使いたい方、申し訳ありませんがいましばらくお待ちください。
さて、検証している上でちょっと困ったことが出てきました。従来動いていたテストコードの一部が、JavaSE 7ではコンパイルもできなくなってしまったのです。これはJavaSE 7の不具合か?と思い、調査してみました。
日本語のテストメソッド名
製品のクラス名やメソッド名では使いませんが、開発時のユニットテストのメソッド名やクラス名は、最近は、基本的に日本語で書くようになりました。これまで日本語メソッド名で特に問題が起こっていなかったことと、テストのレポートの出力がアルファベットのキャメルケースに比べ圧倒的に見やすいからです。
今回のコンパイルエラーの原因は、これらの日本語のテストメソッド名のいくつかで、
@Test public void ほげ・ふがのテスト() { .... }
のように、「・」(ナカグロ: U+30FB)を使っていたことでした。
Character.isJavaIdentifierPart
CharacterクラスのisJavaIdentifierPartメソッドを使用して、ナカグロがJavaの識別子(の最初の文字以外)に使用可能かどうか確かめてみます。
System.out.println(Character.isJavaIdentifierPart('・'));
このコードをJavaSE 6で実行するとtrueに、JavaSE 7で実行するとfalseになりました。
Javadocによると、次のどれかがtrueであればこのメソッドはtrueを返すようです。
- 汎用文字である
- 通貨記号である ('$' など)
- 連結句読点文字である ('_' など)
- 数字である
- 数値汎用文字である (ローマ数字文字など)
- 連結マークである
- 非スペーシングマークである
- isIdentifierIgnorable(codePoint) がその文字について true を返す
しかし、この仕様自体はJavaSE 6でも7でも違いはないようです。
ソースを覗いてみると、どうやらここから内部的に呼ばれているjava.lang.CharacterData00というクラスの実装が、6と7でだいぶ変わっているらしいことがわかりました。
UnicodeData
どのようにして、この修正が行われたのかを調べてみます。OpenJDKのプロジェクトからJava SE 7のソースを取得して見てみると、このjava.lang.CharacterData00というクラスはビルド時に自動生成されていることがわかりました。
- 元となるテンプレート: jdk/make/tools/GenerateCharacter/CharacterData00.java.template
- データ: jdk/make/tools/UnicodeData/以下
- ジェネレータ: jdk/make/tools/src/build/tools/generatecharacter/GenerateCharacter.java
こんな感じみたいです。テンプレートやジェネレータにはナカグロ(U+30FB)がハードコードされているようには見えなかったので、ナカグロを持つデータ(UnicodeData.txt)のログを見てみます。
$ hg log UnicodeData.txt チェンジセット: 3157:13bbabfee6d4 ユーザ: peytoia 日付: Wed Nov 24 14:13:37 2010 +0900 要約: 7002398: Apply Corrigendum #8 for Unicode 6.0.0 チェンジセット: 3150:3207aa4438fc ユーザ: peytoia 日付: Wed Nov 17 01:02:20 2010 +0900 要約: 6959267: Support Unicode 6.0.0 チェンジセット: 1134:1729e34a0287 ユーザ: peytoia 日付: Fri Apr 10 11:51:36 2009 +0900 要約: 6404304: RFE: Unicode 5.1 support チェンジセット: 0:37a05a11f281 タグ: jdk7-b24 ユーザ: duke 日付: Sat Dec 01 00:00:00 2007 +0000 要約: Initial load
JavaSE 7の開発中、Unicode5.1、Unicode 6.0と段階的にサポートされてきたようです。5.1サポート時とその前の差分を見てみると。。。
$ hg diff -r0 -r1134 UnicodeData.txt (snip) @@ -8632,7 +10239,7 @@ 30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; 30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; 30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; -30FB;KATAKANA MIDDLE DOT;Pc;0;ON;;;;;N;;;;; +30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;; 30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; 30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; 30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; (snip)
ありました!30FBの「Pc」が「Po」に変更されています。
このUnicodeData.txtは、見覚えがありました。unicode.orgで配布しているやつですね。
unicode.orgのサイトで、このPcとかPoの意味を調べてみると、
Pc | Connector_Punctuation | a connecting punctuation mark, like a tie |
Po | Other_Punctuation | a punctuation mark of other type |
と、ありました。つまり、変更前は「連結句読点文字(Pc)」だったのが、「その他の句読点文字(Po)」に変更されたため、Javaの識別子として使用できる文字ではなくなったということですね。
Unicodeの変更履歴を読んでみると、2005年にリリースされた4.1の変更で以下のような記述を見つけました:
U+30FB KATAKANA MIDDLE DOT and U+FF65 HALFWIDTH KATAKANA MIDDLE DOT were changed from gc=Pc to gc=Po. See PRI #55
結構前に変更されていたんですね。JavaSE 6のリリースより前みたいですが、JavaSE 6はこの変更前のUnicodeをベースにしてたんでしょうか。
結論
つまり、JavaSE 7でメソッド名にナカグロ(U+30FB)が使えなくなったのは、Unicodeの仕様変更によるものであり、不具合ではないということです。疑ってすみませんでした。
おまけ
原因を調べてたときに、「もしかしてナカグロ以外の文字でも使えなくなっているものがあるんでは?」と思い、とりあえずJIS X 0213:2004の文字を全部チェックしてみました。
(表示にはシーオーリポーツ ビュアーが必要です。)
背景が青いのが識別子に使える文字、白いのが使えない文字です。JavaSE 6では1面1区6点のナカグロが使えることになっていますが、JavaSE 7では使えないことがわかります。(ちなみに、上記のUnicodeの変更点でU+30FBのほかにU+FF65というのも出てきますが、JIS X 0213:2004上はどちらも同じ文字です)。
このファイルはXMLテキストですので、手軽にdiffツールで差分を見ることができます。結果、ナカグロ以外に使えなくなっている文字はありませんでした。