Google ColaboratoryでJavaプログラムを動かす

# はじめに
🤔（「Jupyter Notebookとかで共有しやすいからpython使って」と言われたけど、Jupyter NotebookでJavaって使えないのかな？）

👀：[Windows10のWSLでJupyterLab+Javaを使う](https://qiita.com/toritorix/items/4b2e204d34350d3b98a9)

🤔（使えるな？）

🤔（Jupyter NotebookでJava使えるらしいけど、Google Colaboratoryでpython以外の言語使えないのかな？）

👀：[多分間違えてるColaboratoryの使い方(Kotlinを試す)](https://qiita.com/kei0425/items/b9a374bd0f23934fc22b)

🤔（Kotlinがいけるなら同じJVM言語のJavaが使えない道理がないな？）

↓

やってみた

※Jupyter用のKernel使うとかしてないので、変則的なやり方になっている気がする（そもそもcolabでjavaを使うこと自体が変則的という話はさておき）。

# Colab環境にJavaを入れる

```
!apt update
!apt install openjdk-11-jdk
```
Java 13とか14とか入れても良いのだが、現時点では`wget`なり`tar`なりで落としてくる必要があるのでちょっと面倒。
とりあえず上記のコマンドだけで11は入ってくれるので今回は11を採用。

# プロジェクトの作成
その場にプロジェクト作成するとゴチャッとするのでディレクトリを掘ってプロジェクトを作成する。
gradleはデフォルトで4.4.1が入っているのでinitは特にインストール必要なく使える。

外部ライブラリとか全く使わないならjavaコマンドだけで完結するのでgradle無しでいける。

```セル
!mkdir Java
%cd Java
!gradle init
```

Colab(?)の記法詳しくないので理由は知らないけど`cd`は`!`じゃなく`%`じゃないと移動した状態を維持してくれないので注意。
一時的に移動して何かコマンド打って戻りたいとかなら`!cd hoge && hogehoge`のように`&&`でつなげてもよい。

これでプロジェクト自体は作成できたが、gradleのバージョンが古いので設定ファイルを書き換える必要がある。
元のgradle-wrapper.propertiesの`distributionUrl`を任意のバージョンに変更するだけ。
今回はとりあえず現時点で最新の6.4.1にしておく。

```
%%writefile gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-bin.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
```

# build.gradleの変更
外部のライブラリもちゃんと使えるというのを示すために`commons.math3`を使うので、その辺を踏まえてbuild.gradleを変更する。
この辺順番は割とどうでも良いので、コード先に書いてからbuild.gradleを変更で良い。

変更箇所は下記

* dependencies: 外部ライブラリ読み込むなら
* plugins: `id "application"`
* mainClassName: mainメソッドのあるクラス名
* sourceCompatibility: Javaのバージョン

`plugins`と`mainClassName`は実行するときにbuildしてjarを実行じゃなく、`gradle run`で済ませたいので設定。
なんとなく手癖でjunitも書き換えているがcolab上では使わないのでどうでも良い。

```入力セル：build.gradle
%%writefile build.gradle
plugins {
    id 'java'
    id "application"
}

group 'sample'
sourceCompatibility = 1.11

mainClassName = "sample.Main"

repositories {
    mavenCentral()
}

dependencies {
    // The production code uses the SLF4J logging API at compile time
    compile 'org.slf4j:slf4j-api:1.7.30'

    testCompile 'org.junit.jupiter:junit-jupiter:5.5.2'

    // https://mvnrepository.com/artifact/org.apache.commons/commons-math3
    compile group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'

}
```

# Javaプログラムの作成
ディレクトリを掘る。

```
!mkdir -p src/main/java/sample
```

サンプルコードを書く。
なお、`%%writefile hogehoge`でファイルを作成する形になるのでcolab上で補完は働かない。
なので基本的には手元のIDE上とかでコードを書いてcolab上にコピペするのが楽だし安全(補完なしで書くのはだいぶつらい)。

```入力セル：Main.java
%%writefile src/main/java/sample/Main.java
package sample;

import org.apache.commons.math3.ml.distance.ManhattanDistance;

public class Main{
  public static void main(String[] args) {
    System.out.println("Hello Colab!!");

    var d1 = new double[]{1, 1, 1, 1};
    var d2 = new double[]{1, 0, 0, 1};
    System.out.println(new ManhattanDistance().compute(d1,d2));
  }
}
```

# 実際に動かす
```
!gradle run
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/25ddecea-c92e-9984-517a-2d437c95181b.png)

やったぜ！！

完

# ハマりどころとか
Javaに慣れている人だと当然複数クラス記述する場合にクラスを分けたい。
が、うまくいかなかった。

```入力セル：Main.java
%%writefile src/main/java/sample/Main.java
package sample;

public class Main{
  public static void main(String[] args) {
    Messenger sample = new Messenger("Hello Colab for Java!!");
    sample.hello();
  }
}
```

```入力セル：Messenger.java
%%writefile src/main/java/sample/Messenger.Java
package sample;
class Messenger{
    private final String message;
    
    public Messenger(String message){
        this.message = message;
    }

    public void hello(){
        System.out.println(message);
    }
}
```

で2ファイルを作成して`gradle run`を打つと下記のようにエラーが出る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/7469b445-6122-9cc3-ad8b-11d4da04dc11.png)

この辺、ローカル環境では普通に動くのでcolab特有の問題っぽい。

Javaではpublic classは1ファイルに1つしか記述できないがpublicではないclassならいくらでも記述できるので、以下のように全部1ファイル内にまとめてしまえば動作する。
解決策としてはあまりきれいじゃない気もしつつ、colabで動かすコード量ならこれでも問題ないかな、とも思う。

```入力セル：Main.java
%%writefile src/main/java/sample/Main.java
package sample;

public class Main{
  public static void main(String[] args) {
    Messenger sample = new Messenger("Hello Colab for Java!!");
    sample.hello();
  }
}

class Messenger{
    private final String message;
    
    public Messenger(String message){
        this.message = message;
    }

    public void hello(){
        System.out.println(message);
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/be0f2f49-2ade-f94c-9f57-2a5325e567f7.png)

# おわりに
colabでJavaが使えて嬉しい。

とはいえpythonはpyplotで結果を簡単にグラフ表示できるのが強いので、その辺解決できるまでは結局python使うで落ち着きそう。
Javaでもpyplotみたいにcolab上でサクッと結果を可視化できるようになればJava使うの選択肢として無しではないと思うので、そんな感じのことできないか調べたい気持ちがある。

というわけで、もっとpython以外の言語もデータサイエンス・機械学習系で使える環境が整ってほしいなぁ……。