18文字で書くJava

ちょっと前のことだけど、「Javaでセミコロンなしでプログラムを書く - プログラマーの脳みそ」というエントリを読んで、その後 Semicolonless JavaClassless Java を知った。
これはすごい、これは楽しい、と思った。

そして考えてみると、他のパターンでもできるのではないかと思った。
大したことはできなかったが、いくつか思いついたことを書いてみる。


まず Classless Javaenum でも実現できる。こんな感じ。

public enum HelloWorld {
    HelloWorld;
    public static void main(String[] args){
        System.out.println(HelloWorld);
    }
}

さらに enum 使うとダブルクォーテーションもいらなくなる。もちろん日本語は使える。
toString()でもいいけど、せっかくなのでname()を使ってみた。

public enum HelloWorld {
    こんにちは, 世界;
    public static void main(String[] args) {
        System.out.println(こんにちは.name() + 世界.name());
    }
}


Semicolonless Java のほうは、Unicodeエスケープさせるという安直なことしか思いつかなかった。

public enum HelloWorld {
    こんにちは, 世界\u003b
    public static void main(String[] args) {
        System.out.println(こんにちは.name() + 世界.name())\u003b
    }
}

これではがっかり過ぎるので、もうちょっとだけ頑張って Unicode エスケープ するコードと、元に戻すコードを書いた。
いろいろ調べたけど、結局 char をキャストすることで対応できた。かなり力技だけど…。

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Unicoder {

    public static void main(String[] args) throws IOException {
        Unicoder unicoder = new Unicoder();
        String path = "HelloWorld.java";
        BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream(path), "UTF-8"));
        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(unicoder.encode(line));
            // System.out.println(unicoder.decode(line));
        }
        br.close();
    }

    public String decode(String unicodeLine) {
        StringBuffer br = new StringBuffer();
        String[] letters = unicodeLine.split("\\\\u");
        for (String letter : letters) {
            if (!"".equals(letter)) {
                br.append((char) Integer.parseInt(letter, 16));
            }
        }
        return br.toString();
    }

    public String encode(String normalLine) {
        StringBuffer br = new StringBuffer();
        char[] chars = normalLine.toCharArray();
        for (char c : chars) {
            String letter = Integer.toHexString((int) c);
            br.append("\\u");
            for (int i = 0; i < (4 - letter.length()); i++) {
                br.append("0");
            }
            br.append(letter);
        }
        return br.toString();
    }
}

さっきの HelloWorld はこんな感じになる。もちろんこのままコンパイルして、実行できる。

\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0065\u006e\u0075\u006d\u0020\u0048\u0065\u006c\u006c\u006f\u0057\u006f\u0072\u006c\u0064\u0020\u007b
\u0020\u0020\u0020\u0020\u3053\u3093\u306b\u3061\u306f\u002c\u0020\u4e16\u754c\u003b
\u0020\u0020\u0020\u0020\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0073\u0074\u0061\u0074\u0069\u0063\u0020\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0061\u0072\u0067\u0073\u0029\u0020\u007b
\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u3053\u3093\u306b\u3061\u306f\u002e\u006e\u0061\u006d\u0065\u0028\u0029\u0020\u002b\u0020\u4e16\u754c\u002e\u006e\u0061\u006d\u0065\u0028\u0029\u0029\u003b
\u0020\u0020\u0020\u0020\u007d
\u007d


そんなわけで、Javaは18文字(\0123456789abcdefu)で表現できる。前から分かっていたけど。
それにしてもこんなコードがコミットされていたら困るな。ちゃんと動くし。


冒頭にも書いたけど、あんまり大したことはない。でも考えるプロセスが楽しかった。
こうやれば上手く行くんじゃない?あ、だめだ。の繰り返し。
それが楽しい。