Javaの隠された (しかも、ちょっと面白い) 文法 3選

# この記事は？
この記事は**知名度がかなり低そうなJavaの文法**を、独断で3つ選んで紹介するものです。

動作確認したJavaのバージョンは OpenJDK19 ですが、Java8 の時にはこれらの文法が既にありました。

では、早速行ってみましょう。

# 1. ラベル
https://docs.oracle.com/javase/specs/jls/se19/html/jls-14.html#jls-14.7

文(といっても専らforやwhile文)には、 **ラベル** をつけることができます。
for文の中のbreakやcontinueで参照することで、ラベルがついたループを抜けたり、もう一回やり直すことができます。

```java
var list = new ArrayList<List<Integer>>();
        
// マス目を x + y で埋めていくが、 x + y が6以上になった時点でやめる
label:
for(int y=0; y<5; y++){
  list.add(new ArrayList<Integer>());
  for(int x=0; x<5; x++){
    list.get(y).add(x+y);
    if(x + y >= 6){
      // 外側のループを抜ける
      break label;
    }
  }
}

//表示
list.forEach(elm->{
  elm.forEach(str->System.out.print(str));
  System.out.println();
});
```

出力：

```
01234
12345
23456
```

6になった瞬間にy方向への数値追加もやめたことが分かるでしょうか。

# 2. 小数 リテラル
https://docs.oracle.com/javase/specs/jls/se19/html/jls-3.html#jls-3.10.2

### 16数小数リテラル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496507/e2bda1af-0ae6-f803-1f58-900dcb75aeec.png)
**!?**

小数は10進数だけでなく16進数で書くことも可能です。 (いつ使うんだろう...)
小数を `5e-3` (=$5*10^{-3}$) などと書けることは良く知られていると思いますが、eは16進数の桁に用いられるので、16進数の時はPを使います。pは16進小数には必須で、指数部はなぜかBinary(2の累乗)です。

```java
System.out.print(0x1p-1) // 0.5
System.out.print(0x.1p-2) // 0.015625

System.out.print(0x.1) // コンパイルエラー！
System.out.print(0x.1p0) // OK! 0.0625
```

`0x1p-1` = $1 * 2^{-1} = 0.5$
`0x.1p0` = ${16}^{-1} * 2^{0} = 0.0625 * 1 = 0.0625$
`0x.1p-2` = ${16}^{-1} * 2^{-2} = 0.0625 * 0.25 = 0.015625$

(...ハイライトが上手く適用されてない件...)

### float リテラル

おまけで紹介すると、数値には以下の表記法があって、型を書き分けることができます。

```java
int    i  = 6; // int型
float  i2 = 6f; // float型
float  i3 = 6.0f; // float型
double i4 = 6d; // double型
double i5 = 6.0d; // double型
double i6 = 6.0; // double型
```

`(float)3.14` よりも `3.14f` の方がスマートな感じがしませんか、ね？


# 3. マルチキャッチ
https://docs.oracle.com/javase/specs/jls/se19/html/jls-14.html#jls-14.20

Javaでは、try-catch文において、複数の例外についてまとめて同じ処理を書くことができます。
これを **マルチキャッチ(multi-catch)**[^multi] といいます。

```java
import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
      for(int i=0;i<3;i++){
        try {
          someMethod(i);
        } catch(IOException | IllegalArgumentException e){ // マルチキャッチ
          System.out.println(e.toString() + "; もしかして変な要求を送った？");
        } catch(NullPointerException e){
          System.out.println("ぬるぽ。多分APIのエラー。");
        }
      }
    }
    
    public static void someMethod(int i) throws IOException{
      switch(i){
        case 0 -> throw new IOException();
        case 1 -> throw new IllegalArgumentException();
        case 2 -> throw new NullPointerException();
      }
    }
}

```

出力：

```
java.io.IOException; もしかして変な要求を送った？
java.lang.IllegalArgumentException; もしかして変な要求を送った？
ぬるぽ。多分APIのエラー。
```

違う例外で同じ処理をするならできるだけマルチキャッチを使いましょう！
そうするとコンパイル後のクラスファイルも小さくなります[^class]。読みやすさも多少上がるでしょう。

# 終わりに
~~いかがでしたか？~~

Minecraftのジグソーブロック並み[^jigsaw]に誰も使わないような文法ですが、知っているとちょっと面白い...はずです。

# 読むと楽しい
https://docs.oracle.com/javase/specs/jls/se19/html/index.html

[^jigsaw]:データパックなどにて構築物のランダムな生成を可能にするブロック。カスタムディメンションを作るような人しか使わない。
[^multi]: れっきとした公式用語。逆に、普通のcatch節は **"uni-catch"** という。
[^class]: 詳しいことは省きますが、コンパイラはマルチキャッチ節をuni-catchに分解せずともそのまま理解できるためです。