Processing4.0で使っていきたい文法

概要編はこちら [🎉祝 Processing4.0 正式版 🚀 - Qiita](https://qiita.com/TN8001/items/70b7e690b96898eed6fc)

Processing4.0になり、ベースのJavaバージョンがJava17へと大幅に進みました（Processing3.5.4はJava8ベース）
今まで使えなかったいろいろなものが使えるようになりました。

:::note warn
すべての言語機能が使えるわけではありません。
3系でもラムダは使えませんでしたし、4.0もswitch式が使えない等PDE側の制限はあります。
現状は使えなくても、徐々に対応が進むと思われます。
:::

新しい組み込み関数もいくつか追加されています。

詳細はこちら [Changes in 4.0 · processing/processing4 Wiki](https://github.com/processing/processing4/wiki/Changes-in-4.0)
さらに詳細 [processing4/revisions.md at main · processing/processing4](https://github.com/processing/processing4/blob/main/build/shared/revisions.md)

# [Java8](https://www.oracle.com/java/technologies/javase/8-relnotes.html)

### [ラムダ式・メソッド参照・関数型インターフェース](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)


```java:Processing 3.5.4
import java.util.Arrays;

for (int x : Arrays.asList(1, 2, 3, 4, 5)) {
  println(x * x);
}
```
```java:Processing 4.0.1
import java.util.Arrays;

Arrays.asList(1, 2, 3, 4, 5)
  .stream()
  .map(x -> x * x)
  .forEach(PApplet::println);
```
かえって長い...例が悪いですね。


# [Java9](https://www.oracle.com/java/technologies/javase/9-relnotes.html)

### [List.of](https://docs.oracle.com/javase/jp/9/docs/api/java/util/List.html#of-E-)

```java:Processing 3.5.4
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

List<Integer> list = Arrays.asList(1);
list.set(0, 2);
println(list); // [2]
list = Collections.unmodifiableList(list);
list.set(0, 3); // UnsupportedOperationException
```
```java:Processing 4.0.1
import java.util.List;

List<Integer> list = List.of(1);
list.set(0, 2); // UnsupportedOperationException
```
変更する気がないなら、`List.of`は短くていいですね。

### [単一アンダースコアのキーワード化](https://openjdk.org/jeps/213)
```java:Processing 4.0.1
// '_' should not be used as an identifier, since it is a reserved keyword from source level 1.8 on
int _ = 0;
```
普通は使わないので問題ないでしょう（今後破棄に使えるようになったりするんでしょうか？）


# [Java10](https://www.oracle.com/java/technologies/javase/10-relnote-issues.html)

### [var（型推論）](https://docs.oracle.com/javase/jp/10/language/toc.htm)

```java:Processing 3.5.4
int i = 1;
float f = 1f;
String s = "a";
int[] array = { 1, 2, 3 };
HashMap<String, String> map = new HashMap<String, String>();
//HashMap<String, String> map = new HashMap<>(); // ダイアモンド演算子未対応
```
```java:Processing 4.0.1
var i = 1;
var f = 1f;
var s = "a";
//var array = { 1, 2, 3 }; // Array initializer needs an explicit target-type
var array = new int[]{ 1, 2, 3 };
var map = new HashMap<String, String>();
HashMap<String, String> map2 = new HashMap<>(); // ダイアモンド演算子対応
```
変数の位置がそろって見やすいですね（使えるところはすべて使う派です）
配列初期化子だけは残念です。


# [Java11](https://www.oracle.com/java/technologies/javase/11-relnote-issues.html)

### [String.strip](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/String.html#strip())

```java:Processing 4.0.1
println("[" + "\u3000".trim() + "]"); // [　]
println("[" + "\u3000".strip() + "]"); // []
```
全角スペースも削除されます。

### [String.repeat](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/String.html#repeat(int))

```java:Processing 3.5.4
for (int i = 0; i < 10; i++) {
  for (int j = 0; j < 10; j++) {
    if (j < 9 - i) {
      print(" ");
    } else {
      print("*");
    }
  }
  println();
}
```
```java:Processing 4.0.1
for (int i = 0; i < 10; i++) {
  print(" ".repeat(9 - i));
  print("*".repeat(i + 1));
  println();
}
```
その文字列を指定回数繰り返した文字列を作ります。
[processingで階段を作りたいです | teratail](https://teratail.com/questions/5kvs3pyvd3jw3c)


# [Java12](https://www.oracle.com/java/technologies/javase/12-relnote-issues.html)

### [String.indent](https://docs.oracle.com/javase/jp/12/docs/api/java.base/java/lang/String.html#indent(int))
```java:Processing 4.0.1
print("a\n b\n  c".indent(2));
println("d");
//  a
//   b
//    c
//d
```
いつ使いましょうかね。

### [CompactNumberFormat](https://docs.oracle.com/javase/jp/12/docs/api/java.base/java/text/CompactNumberFormat.html)
```java:Processing 4.0.1
import java.text.NumberFormat;

NumberFormat fmt = NumberFormat.getCompactNumberInstance();
println(fmt.format(1000)); // 1,000
println(fmt.format(10000)); // 1万
println(fmt.format(100000)); // 10万
```
ほしい時もありそうですね。

# [Java13](https://www.oracle.com/java/technologies/javase/13-relnote-issues.html)

### [JapaneseEra.REIWA](https://docs.oracle.com/javase/jp/13/docs/api/java.base/java/time/chrono/JapaneseEra.html#REIWA)
```java:Processing 3.5.4
import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;

String s = JapaneseDate.now().format(DateTimeFormatter.ofPattern("Gy年M月d日"));
println(s); // 平成34年8月14日
```
```java:Processing 4.0.1
import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;

String s = JapaneseDate.now().format(DateTimeFormatter.ofPattern("Gy年M月d日"));
println(s); // 令和4年8月14日
```
令和も問題ありません。

# [Java14](https://www.oracle.com/java/technologies/javase/14-relnote-issues.html)
:::note warn
残念ながらPDE未対応です。
* caseのカンマ区切り複数ラベル
* switch式
:::

# [Java15](https://www.oracle.com/java/technologies/javase/15-relnote-issues.html)

### [テキストブロック](https://docs.oracle.com/en/java/javase/13/text_blocks/index.html)
```java:Processing 3.5.4
String json = 
  "{\n" +
  "  \"key\": \"hoge\",\n" +
  "  \"value\": 1\n" +
  "}";
  
println(json);
//{
//  "key": "hoge",
//  "value": 1
//}
```
```java:Processing 4.0.1
String json = """
  {
    "key": "hoge",
    "value": 1
  }""";

println(json);
//__ ←トリミングされていない！
//  {
//    "key": "hoge",
//    "value": 1
//  }
```

:::note warn
使えはしますが「トリミングされない・自動フォーマットするとずれる」為、まだ実用は無理そうです（よほど`"`を大量に使いたい時ぐらいか？）
:::

### [String.formatted](https://docs.oracle.com/javase/jp/15/docs/api/java.base/java/lang/String.html#formatted(java.lang.Object...))
```java:Processing 3.5.4
println(String.format("%s,%d", "a", 1)); // a,1
```
```java:Processing 4.0.1
println("%s,%d".formatted("a", 1)); // a,1
```
ちょっと短くなりますね。


# [Java16](https://www.oracle.com/java/technologies/javase/16-relnote-issues.html)

### [Stream.toList](https://docs.oracle.com/javase/jp/16/docs/api/java.base/java/util/stream/Stream.html#toList())
```java:Processing 4.0.1
import java.util.List;
import java.util.stream.Collectors;

List<Integer> list = List.of(1, 2, 3, 4, 5);
list = list.stream().map(x -> x * x).toList();
//list.set(0, 0); // UnsupportedOperationException
//list.add(6); // UnsupportedOperationException
println(list); // [1, 4, 9, 16, 25]

list = list.stream().collect(Collectors.toList());
list.set(0, 0);
list.add(6);
println(list); // [0, 4, 9, 16, 25, 6]
```
「なぜこのタイミングで？」とは思いますが、用途に合っていれば使っていきましょう。

:::note warn
残念ながらPDE未対応です。
* パターンマッチング（instanceof）
* レコードクラス
* 内部クラスにstaticメンバーが定義可能
:::


# [Java17](https://www.oracle.com/java/technologies/javase/17-relnote-issues.html)

### [HexFormat](https://docs.oracle.com/javase/jp/17/docs/api/java.base/java/util/HexFormat.html)

```java:Processing 3.5.4
color c = color(255, 128, 0);
println("#" + hex(c, 6)); // #FF8000
```
```java:Processing 4.0.1
import java.util.HexFormat;

HexFormat hex = HexFormat.of().withUpperCase();
byte[] bytes = { (byte)255, (byte)128, (byte)0 };
println("#" + hex.formatHex(bytes)); // #FF8000
```
例は意味がありませんが、便利な時もあるでしょう。

:::note warn
残念ながらPDE未対応です。
* シールクラス
:::

# 組み込み関数
### [IntList.random（FloatList・StringList）](https://github.com/processing/processing4/blob/58ff6a3ca5c9c2f26a81d4014edc5d5ba0abf4c7/build/shared/revisions.md#data-updates)

```java:Processing 3.5.4
IntList list = new IntList();
list.append(1);
list.append(2);
list.append(3);
println(list.get((int)random(list.size())));

// 壊していいなら
list.shuffle();
println(list.get(0));
```
```java:Processing 4.0.1
IntList list = new IntList();
list.append(1);
list.append(2);
list.append(3);
println(list.random());
//println(random(list)); // こうではない
```
確かに冗長だったが、なぜ`PApplet.random`にオーバーロードを追加しないのか。


### [surfaceを置き換える関数](https://github.com/processing/processing4/blob/58ff6a3ca5c9c2f26a81d4014edc5d5ba0abf4c7/build/shared/revisions.md#feature-improvements-in-progress)
```java:Processing 3.5.4
surface.setSize(300, 200);
surface.setResizable(true);
surface.setLocation(200, 200);
surface.setTitle("Processing");
```
```java:Processing 4.0.1
void setup() {
  windowResize(300, 200);
  windowResizable(true);
  windowMove(200, 200);
  windowTitle("Processing");
}

void draw() { }

void windowResized() {
  println("windowResized", width, height);
}

void windowMoved() {
  println("windowMoved", windowX, windowY);
}
```
そのままですね。
イベントに引数付きはありません。

:::note alert
現在リサイズするとフリーズします。
[Freezing on window resize · Issue #507 · processing/processing4](https://github.com/processing/processing4/issues/507)
:::