セミコロンレスJavaで戻り値のあるメソッドを定義する(ただし返ってこない)の解説

これがなぜコンパイルを通るのか?という疑問を見かけたので解説してみます。

到達不能文

例えば while(false) { ... } とした時、この while ブロック内の文は絶対に実行されません。 このように絶対に実行されない文を 到達不能 と表現し、到達不能な文がある場合はコンパイルエラーになります。

次のような内容で Sample1.java を作成して javac してみてください。

public class Sample1 {
    public void whileSample() {
        while(false) {
            System.out.println("到達不能!");
        }
    }
}

次のようなエラーになります。

Sample1.java:3: エラー: この文に制御が移ることはありません
        while(false) {
                     ^
エラー1個

for 文でも同じ事ができます。

public class Sample2 {
    public void forSample() {
        for(;false;) {
            System.out.println("到達不能!");
        }
    }
}
Sample2.java:3: エラー: この文に制御が移ることはありません
        for(;false;) {
                     ^
エラー1個

try 文はエラーメッセージは違いますが、次のようコードは到達不能な文を含むのでコンパイルエラーになります。

public class Sample3 {
    public void trySample() {
        try {
            System.out.println("到達可能");
        } catch(RuntimeException e) {
            System.out.println("到達可能");
        } catch(IllegalArgumentException e) {
            System.out.println("到達不能!");
        }
    }
}
Sample3.java:7: エラー: 例外IllegalArgumentExceptionはすでに捕捉されています
        } catch(IllegalArgumentException e) {
          ^
エラー1個

特別扱いの if

ここまで whilefortry の到達不能な文を含むコードがコンパイルエラーになる例を見てきました。 if 文でも同じような事ができるかと思いきや、次のコードはコンパイルできてしまいます。

public class Sample4 {
    public void ifSample() {
        if(false) {
            System.out.println("到達不能!");
        }
    }
}

到達不能な文を含んだ if 文はどのようにコンパイルされたのか、 javap -c Sample4 して確認してみましょう。

Compiled from "Sample4.java"
public class Sample4 {
  public Sample4();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void ifSample();
    Code:
       0: return
}

ご覧の通り、 if 文が綺麗さっぱり消えていますね。

では、 if の条件式を true に変えてコンパイルして javap してみましょう。 (クラス名などは少し変えてあります)

Compiled from "Sample5.java"
public class Sample5 {
  public Sample5();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void ifSample();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String 到達可能
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

if 文の中身はありますが、条件を評価している部分がなくなりました。

if がこのように特別扱いになっているのは、次のようなコードを書けるようにするためです。

static final boolean DEBUG = true;

void sample() {
    if(DEBUG) { System.out.println("logging"); }
}

先述の特徴があるので、定数 DEBUGtrue ならロギングされるけども、 false ならロギングのコードがクラスファイルからも消える、という感じです。

return を書かずに戻り値のあるメソッドを定義する

return 文にはどうしてもセミコロンを書く必要があります。 それが故にセミコロンレスJavaでは戻り値のあるメソッドを定義することはできないと考えられていました。

私も「どのようにすればセミコロンを省略して return が書けるのか」と考えては挫折を繰り返してきましたが、 あるとき「セミコロンを省略して return が書けないなら、そもそも return を書かなければ良いのでは」と発想の転換をしてみました。

前半で述べた通り、到達不能な文を含むとコンパイルエラーになります。 逆に考えると、無限ループは到達可能なのでコンパイルを通るし、無限ループの後ろは到達不能なので何を書いてもコンパイルエラーになる、ということですね。

while(true) {
    //到達可能
}
//到達不能

これにより冒頭に記載したツイートの通り、セミコロンを書かずに戻り値のあるメソッドを定義できました。

public class Semicolonless {

    String get() {
        while (true) {
        }
    }
}

ちなみにセミコロンはともかく、 return を書かずに戻り値のあるメソッドを定義する方法としては例外を投げるというのもあります。 (例えば Thread.destroy()

戻り値のあるメソッドに return 文なんて要らんかったんや!!!

まとめ

  • 一見不可能に思えることでも考え方を変えることで解決する場合がある
  • とはいえ解決したところで役に立たないものもある

GitHubで毎日草生やし続ける運動を終了する

GitHubで毎日草生やし続ける運動とは

GitHubはコミットしたりプルリクするとプロフィールページのタイルっぽいやつが緑になります。 緑になるから「草を生やす」って比喩してるんですけど、それを毎日続けて緑で埋め尽くそうというものです。

進捗

7月最後の週ぐらいに草だらけになりました。

Slackでわざわざ報告している図。

それからも毎日草生やしてたので400日ぐらいは継続できていると思います。

なぜやろうと思ったか

三十路になって「これからもコードを書いていられるのだろうか?(環境というよりは自分のモチベーション的な意味で)」と思うようになりました。 なので好きかどうか自分自身を試そうかなー、と。

やってみて得たもの

やる前に思ってたよりもずっと楽しんで続けられたので、やっぱり自分はコード書くの好きなんだな、と思えました。これは嬉しい。

あと、大したコードは書けてないですが、サンプルやらビルドスクリプトが溜まってきて何かと役立っています。

なぜやめようと思ったか

「継続」を目的としていたので、書きたいコードが思いつかない日はREADME.mdを修正するといったセコい草もたまには生やしていましたが、もうそうまでして草生やすのは面倒に思えてきました。

それに、読書のような草が生えない活動にももっと時間を使いたいなーと思い始めました。

当初の目標であった一年は継続できたので、やめるのにも未練は無いですし。 (でもなんか気持ちの整理的にやめることは記しておきたくてこのエントリを書いてる)

まとめ

  • コード書くのが好きだと再確認できて個人的には意義がある試みでした
  • 草生やし運動は人によって合う・合わないがあるので特別おすすめはしません
  • 一年後、プロフィールページが不毛の地と化していたら嘲笑ってください