20201022のJavaに関する記事は12件です。

[day: 5]Javaの基本をまとめました

Javaの基本をまとめました

Javaの基本構文を確認できるチートシートとして作成しました。

出力

System.out.println("Hello World");

//文字列と数値を一緒に出力すると数値は文字列に自動変換される
Ststem.out.println("私は" + 20 + "歳です");
//私は20歳ですが出力される

コメントアウト

// コメントアウト

データ型

文字列や整数などの型をデータ型という
文字列: String
整数: int

変数

変数の定義

//データ型変数名の順番で宣言する
String name;

//変数に値を代入する
name = "佐藤";

//佐藤が出力される
System.out.println(name);

変数の初期化

変数の定義と代入は同時に行うことができる。

//Stringのデータ型で変数名nameに佐藤の値を代入
String name = "佐藤";

//佐藤が出力される
System.out.println(name);

変数の再定義と再代入

再定義は不可能

//変数numberを定義
int number = 1;

//もう一度変数numberを定義するとエラーになる
int number = 1;

再代入は可能

//numberの値は1
int number = 1;

//numberの値は2(値が上書きされている)
number = 2;

自己代入

//numberに1を代入
int number = 1;

//元の値である1を利用して、さらにそこに1を足した数をnumberに再代入する
number = number + 1;

//2が出力される
System.out.println(number);

この書き方には省略形がある

number += 1;  //number = number + 1;
number -= 1;  //number = number - 1;
number *= 1;  //number = number * 1;
number /= 1;  //number = number / 1;
number %= 1;  //number = number % 1;

キャスト

求める型が変数の型と異なるときに強制的に型を指定することができる。これをキャストと呼ぶ。

int number1 = 1;
int number2 = 2;
System.out.println((double)number1 / number2);
//(double)をつけたnumber1は強制的に1.0に変換される

条件分岐

if

if文の基本形

if(条件式1){
  条件式1がtrueなら実行する処理
} else if(条件式2){
  条件式2がtrueなら実行する処理
} else {
  上記の条件が全てfalseなら実行する処理
}

switch

switch文の基本形
breakはswitch文を抜け出すために必要な記述。これが無いと全ての処理を実行してしまう。

switch (処理){
  case 値1:
    処理の戻り値が値1なら実行する処理
    break;
  case 値2:
    処理の戻り値が値2なら実行する処理
    break;
  default:
    どのcaseにも当てはまらない場合に実行する処理
    break;
}

繰り返し処理

while

whileの基本形
条件がtrueで有る限り処理を繰り返し行うことができる。
条件はいつかはfalseになるように設定しないと無限ループしてしまう。

while(条件){
  条件がtrueなら実行する処理
}

記述例
変数numberの値が100以下ならばそのnumberを出力する繰り返し処理

int number = 1;

while(number <= 100){          //numberが100以下ならtrueを返す
  System.out.println(number);  //numberの値を出力
  number ++;                   //numberに1を足す
}

for

forの基本形

for(変数の定義; 条件; 値の更新){
  条件がtrueなら実行する処理
}

記述例
変数numberの値が100以下ならばそのnumberを出力する繰り返し処理

for(int number; number <= 100; number ++){
  System.out.println(number);
}

繰り返し処理の強制終了

繰り返し処理の中でif文breakを使うことで特定の条件になったら処理を終了させることができる。

//numberの値が100以下ならnumberを出力する繰り返し処理
for(int number = 1; number <= 100; number ++){
//条件分岐でnumberの値が5ならば繰り返し処理を強制終了させる
  if(number == 5){
    break; //繰り返し処理の強制終了
  }
}

特定の繰り返し処理をスキップ

繰り返し処理の中でif文continueを使うことで特定の値の場合の処理をスキップできる。

//numberの値が100以下ならnumberを出力する繰り返し処理
for(int number = 1; number <= 100; number ++){
//条件分岐でnumberの値が5ならば処理をスキップしつつ繰り返し処理を続行する
  if(number == 5){
    continue; //次のループを開始する
  }
  System.out.println(number);
}
//今回の処理では値が5の場合のみ出力されない

配列

値をまとめて配列として変数に代入することができる。
その際にデータ型は配列を表すために[ ]がつくことに注意。
また、値は{ }で囲んで、それぞれの値は,で区切られる。
[ ]{ }を間違えないように注意する。

//数字の配列であるnumbersを定義する
int[] numbers = {1, 2, 3, 4, 5};

配列にはインデックス番号が付与される。
これは配列に入っている値の順番を意味しており、0からスタートする。
例えば配列の1番目の要素のインデックス番号は0である。
配列のインデックス番号を指定することで特定の値を取り出すことができる。

int[] numbers = {1, 2, 3, 4, 5};

//配列numbersの1番目の要素を指定する
System.out.println(numbers[0]);
//1が出力される

拡張for

配列用の繰り返し処理として拡張for文が用意されている
拡張for文の基本形

//数字の配列であるnumbersを定義
int[] number = {1, 2, 3, 4, 5};

//numbersの要素を順番に一つずつnumに代入しながらforで繰り返し処理を行う
//forの処理は配列の要素の数だけ行う
for(int num: numbers){
  System.out.println(num);
}
//結果として配列にある全ての値が出力される

メソッド

メソッドの定義

メソッドは処理をまとめたもの。
必ずclassの中に定義すること。
呼び出すことでそのメソッドでまとめられた処理を実行することができる。
returnで戻り値を指定することで呼び出し元に値を返すことができる。

メソッド定義の基本形

public static 戻り値のデータ型 メソッド名(データ型 引数名){
  実行する処理
  return 戻り値として返す値
}

メソッドのオーバーロード

原則として同じメソッド名を定義することはできない。これはどのメソッドを実行すれば良いのかわからなくなってしまうためである。
引数の型や数が異なるのであれば同じメソッド名を定義することができる。

クラス

クラス名は大文字から始める。
クラスを定義するファイルはクラス名.javaとする。
他のクラスのメソッドを呼び出す際にはクラス名.メソッド名()とする。
クラスはオブジェクト指向の概念であるオブジェクトの設計図。
その設計図から作られた子どもがインスタンスと呼ばれる。

class Main{
  public static void main(String args[]){
    //UserクラスのsayHello()メソッドの呼び出し
    User.sayHello()
  }
}

ライブラリ

他の人が作ったクラスをライブラリという。
ライブラリを活用することで開発の幅が広がる。

インポート

ライブラリを使用できるようにファイルに読みませること。
元々すでにJava自体が読み込んでいて使用できるようになっているクラスもある。

//LocalDateクラスを読み込む
import java.LocalDate

class Main{
  //省略
}

オブジェクト指向

現実世界のモノは情報と振る舞いを持っている。
それを表現するためにクラスを定義している。
※詳しくは別の資料を参考にしてください。この記事ではJavaの基本文法のチートシートに重きをおきます。

インスタンスの生成

//Personクラスのインスタンスをpersonという名前で生成
Person person = new Person();

インスタンス

インスタンスフィールド

インスタンスが持つ情報をインスタンスフィールド

//インスタンスフィールドの定義
public String name;
//インスタンスフィールドに値をセットする
person.name() = "佐藤";
this

thisを使用する自身が持つインスタンスフィールドの値にアクセスできる。

class Person {
  //インスタンスフィールドにnameをセット
  public String name;
  //コンストラクタを定義
  Person(String name){
    //インスタンスフィールドのnameに引数で受けとたnameを代入
    this.name = name;
  }
}
コンストラクタ

インスタンスの生成時に実行される処理を定義できる。
定義の基本形

class Person {
  クラス名(引数のデータ型 引数){
    処理
  }
}

this()を使用すると別のコンストラクタを呼び出すことができる。
これを利用することでコンストラクタで重複する部分を共通化することができる。

//別のコンストラクタを飛び出して、このコンストラクタで定義できる。
this(引数, 引数);

インスタンスメソッド

インスタンスが持つ振る舞いをインスタンスメソッドと呼ぶ。
インスタンスメソッドはクラスに定義しているが、実際はインスタンスに属している。
staticはいらない

public void hello(){
  System.out.println("hello");
}
//インスタンスメソッドの呼び出し
person.hell();

クラスフィールド

インスタンスフィールドはインスタンスに属する値ですが、クラスに属するクラスフィールドも定義できる。
インスタンフィールドと異なりstaticが必要になるので注意。
クラスフィールドの基本形

class Person {
  public static データ型 クラスフィールド名;
}

クラスフィールドへのアクセスはクラス名.クラスフィールド名で行う。

クラス名.クラスフィールド名

カプセル化

書き換えて欲しく無いものを隠すことができる。
クラスの外からアクセスできないようにするにはprivateを指定することで実現できる。
クラスの外からアクセスできるようにするにはpublicを指定する。

ゲッター

privateで指定した値を安全に取り出すためにメソッドとして定義したもの。
getフィールド名とするのが一般的。

セッター

privateで指定した値を外から書き換えるために定義するメソッドのこと。
setフィールド名とするのが一般的。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】ExecutorServiceで特定の処理を別スレッドで実行する【無限ループを回避】

はじめに

Javaで特定の処理を別スレッドで実行するサンプルです。
とある処理で無限ループが発生した際(指定時間内に処理が終了しなかった際)処理を中断し、エラーを発生させるということをする必要があったのでその時の備忘録となります。

サンプル

main.java
package main;


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


public class Main {

    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        int c = 3;

        ExecutorService exec = Executors.newSingleThreadExecutor();
        // 別スレッドで処理を実行
        Future<Integer> future = exec.submit(new ExcutorSample(a, b, c));
        Integer result = 0;
        try{
            // 10秒間待機する。正しく処理が終了する場合は、計算結果が返ってくる。10秒経過したら例外をスロー
            result = future.get(10, TimeUnit.SECONDS);
        } catch(TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            // 処理を中断する。正常に処理が終了していた場合でもこの処理は無害。
            future.cancel(true);
        }

        System.out.println(result);

    }

    public static class ExcutorSample implements Callable<Integer>{
        private int a;
        private int b;
        private int c;

        public ExcutorSample(int a, int b, int c){
            this.a = a;
            this.b = b;
            this.c = c;
        }

        @Override
        public Integer call() throws Exception {
            // 無限ループする処理が組み込まれている
            boolean loopFlg = true;
            while(loopFlg) {
                Thread.sleep(1000);
                System.out.println("ループ中");
            }
            return a + b + c;
        }
    }
}

実行結果

ループ中
ループ中
ループ中
ループ中
ループ中
ループ中
ループ中
ループ中
ループ中
ループ中
java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:205)
    at main.Main.main(Main.java:24)
0

おわりに

無限ループは発生させるな

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】Listにデータを追加する方法(add,addAll)

プログラミング勉強日記

2020年10月22日
addAllの使い方がいまいち理解できてなかったのでListにデータを追加する方法まとめる。

値を追加するaddの使い方

 addメソッドは値を追加することができる。Listの末尾や位置を決めて挿入することができる。

末尾に追加
List<Integer> list = new ArrayList<Integer>();
// integer型のListの末尾に値1を追加
list.add(1);

 挿入位置を決める場合は、2つの引数を指定する。第1引数は挿入する場所を、第2引数は挿入する値を指定する。

挿入位置を決める
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(3);
list.add(4);
// Listの1と3の間に2を入れる
list.add(1,,2);

値をまとめて追加できるaddAllの使い方

 addAllは複数の値をまとめて追加することのできるメソッド。

// Listを2つ用意してlistにlist2の値を追加する
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);

List<Integer> list2 = new ArrayList<Integer>();
list2.add(5);
list2.add(6);
list2.add(7);
list2.add(8);
list.addAll(list2);

 

// Listを定義しなくても上記のコードと同様の結果になる
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.addAll(Arrays.asList(5, 6, 7, 8));

 addAllメソッドもaddメソッド同様に、追加する位置を指定できる。処理の方法も同様で、引数を指定する。

挿入位置を決める
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);

List<Integer> list2 = new ArrayList<Integer>();
list2.add(5);
list2.add(6);
list2.add(7);
list2.add(8);
list.addAll(1, list2);

参考文献

Java 配列からリストを作成する(addAll/asList)
【3分でわかるJavaの基礎】Listにデータを追加する方法(add,addAll)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】オーバーライドとオーバーロードってなに

今一つアウトプットの勘所というのがわかりませんが、まぁ備忘録替わりです。
書き方云々で悩むよりはよいでしょうということであまり考えずにやっていきましょう。

IT系(?)新卒一年目、学生時代にコンピュータ系の経験なしという死海に投げ込まれたナメクジのようなもんです。
JavaSE11Silverとりたくて黒本やってるのですが、個人的躓きポイントとしてあるのがオーバーライドとオーバーロードというものです。紛らわしい。名前つけた人はそうとは思わなかったんでしょうか。思わなかったでしょうな。人の心がない。大体6文字あって4文字同じなのですから多数決で言えば同じでしょう。

*以下の記述は精密性、正確性ともにかけているであろうざっくりメモです。信じてはなりません。

端的に
【オーバーライド】
・スーパークラスで定義されているメソッドをサブクラスでも使えるように再定義したもの。
ちなみに、スーパークラスは継承された側でサブクラスは継承した側のクラスです。
・オーバーライドされた側、した側について、戻り値、メソッド名、引数が同じが同じでなければならない。
・アクセス制限レベル(publicとかprivateとかabstractとかfinalとか)について、オーバーライドする側はオーバーライドされた側より緩いアクセス制限でなければならない
(スーバークラスのオーバーライドされる側がpublicで、サブクラスのオーバーライドする側がprivateとかはできない。)
・finalがついているメソッドをオーバーライドすることはできない。
・オーバーライドされるメソッドのアクセス修飾子がabstractであるとき、そのメソッドはオーバーライドされなければならない。
 されなかった場合、クラスそのものがabstractクラスになる。(ところでabstractクラスってどんなだっけ...)

【オーバーロード】
・同一クラス内で、同一のメソッド名で、引数の方、引数の数、並びが異なるメソッドを複数作ること。
・戻り値の方、アクセスレベル、引数名、throw節が異なるとオーバーロードできず、コンパイルエラーになる。

*オーバーロードは継承されたクラスのメソッドを継承したクラスでも使えるようにするもの。
*オーバーロードは、同一クラス内で、引数の型や数を変えたメソッドを作るもの。

みたいです。

ちなみに、それぞれ英訳すると
overrideは …の上に乗る。
overloadは 過負荷にする。加重積載する。
という意味だそうで、

オーバーライドは親クラスの上に乗っかるイメージ、オーバーロードはクラスに同じメソッドを過積載するイメージにすると覚えやすかったりするんでしょうかね。

最後に、これ記事書いてるとき右側にプレビュー見えるんですけど可読性死ぬほど低いっすね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Gradle Quick reference

Docker Hub の Gradle 公式イメージの説明書き の日本語訳。

Gradle とは?

Gradle は、ビルドの自動化と多言語開発のサポートに重点を置いたビルドツールです。
任意のプラットフォームでソフトウェアを構築、テスト、公開、デプロイする場合、 Gradle はコードのコンパイルとパッケージ化から Web サイトの公開までの開発ライフサイクル全体をサポートできる柔軟なモデルを提供します。
Gradle は Java, Scala, Android, C/C++, Groovy などの複数の言語とプラットフォームにわたるビルド自動化をサポートするように設計されており、Eclipse, IntelliJ, Jenkins などの開発ツールや継続的インテグレーションサーバーと緊密に統合されています。

このイメージの使い方

Gradle プロジェクトの構築

ビルドする Gradle プロジェクトのディレクトリから下記を実行します。

docker run --rm -u gradle -v "$PWD":/home/gradle/project -w /home/gradle/project gradle gradle <gradle-task>

上記のコマンドは root として実行されるのを避ける為に uid/gid 1000(ユーザー gradle)を使用して実行されることに注意してください。
ボリュームをマウントしており、 Docker を実行している uid/gid が 1000 でない場合は、ユーザー root( -u root ) として実行する必要があります。
root もデフォルトであるため、単純にユーザーを指定しないこともできます。

ライセンス

このイメージに含まれているソフトウェアのライセンス情報を表示します。
すべての Docker イメージと同様に、これらには他のライセンスの下にある可能性のある他のソフトウェア(ベースディストリビューションの Bash など、含まれているプラ​​イマリソフトウェアの直接的または間接的な依存関係)も含まれている可能性があります。
自動検出できたいくつかの追加のライセンス情報は、 repo-info リポジトリの gradle/ ディレクトリにある可能性があります。
ビルド済みのイメージの使用に関しては、このイメージの使用が、そこに含まれるすべてのソフトウェアに関連するライセンスに準拠していることを確認するのはイメージユーザーの責任です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Gradle クイックリファレンス 日本語訳

Docker Hub の Gradle 公式イメージの説明書き の日本語訳。

Gradle とは?

Gradle は、ビルドの自動化と多言語開発のサポートに重点を置いたビルドツールです。
任意のプラットフォームでソフトウェアを構築、テスト、公開、デプロイする場合、 Gradle はコードのコンパイルとパッケージ化から Web サイトの公開までの開発ライフサイクル全体をサポートできる柔軟なモデルを提供します。
Gradle は Java, Scala, Android, C/C++, Groovy などの複数の言語とプラットフォームにわたるビルド自動化をサポートするように設計されており、Eclipse, IntelliJ, Jenkins などの開発ツールや継続的インテグレーションサーバーと緊密に統合されています。

このイメージの使い方

Gradle プロジェクトの構築

ビルドする Gradle プロジェクトのディレクトリから下記を実行します。

docker run --rm -u gradle -v "$PWD":/home/gradle/project -w /home/gradle/project gradle gradle <gradle-task>

上記のコマンドは root として実行されるのを避ける為に uid/gid 1000(ユーザー gradle)を使用して実行されることに注意してください。
ボリュームをマウントしており、 Docker を実行している uid/gid が 1000 でない場合は、ユーザー root( -u root ) として実行する必要があります。
root もデフォルトであるため、単純にユーザーを指定しないこともできます。

ライセンス

このイメージに含まれているソフトウェアのライセンス情報を表示します。
すべての Docker イメージと同様に、これらには他のライセンスの下にある可能性のある他のソフトウェア(ベースディストリビューションの Bash など、含まれているプラ​​イマリソフトウェアの直接的または間接的な依存関係)も含まれている可能性があります。
自動検出できたいくつかの追加のライセンス情報は、 repo-info リポジトリの gradle/ ディレクトリにある可能性があります。
ビルド済みのイメージの使用に関しては、このイメージの使用が、そこに含まれるすべてのソフトウェアに関連するライセンスに準拠していることを確認するのはイメージユーザーの責任です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IntelliJで依存として設定されたライブラリのソースをプロジェクトの別モジュールとして設定する

例えば A というリポジトリがあり、複数のプロジェクトで共通に使用される auth-shared というライブラリを依存として設定してあるとする。

IntelliJで普通に A というリポジトリを開くと auth-shared は外部ライブラリとしてインポートされ、 auth-shared の修正をしたい場合は auth-shared プロジェクトを開き、修正し、 maven install し、 A でリロードするといったことをしなければならず、頻繁に修正したいときや試行錯誤したいときには不便。

これから述べる方法により、このような場合に Aauth-shared を同じプロジェクトで開き、 auth-shared を修正したらすぐに修正した動作を確認できるようになる。

手順

依存ライブラリのローカルのソースをモジュールとしてプロジェクトに追加する

IntelliJのメニュー "File" -> "Module from Existing Sources..." からプロジェクトに追加したいモジュールのルートディレクトリまたはMavenならpom.xmlを選択する。

Project Structure からDependenciesの設定を行う

Project Structure->Modules->依存する側のモジュールを選択->Dependenciesタブ-> "+"ボタンから "Module Dependency" を押し、依存として追加する。

Dependenciesのリストの上部ほど優先して参照されるので、元々の依存よりも上の位置に追加した依存を移動させる(Macなら Option+↑ で移動させるのが楽)。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java--PowerPointの図形に影をつける方法

PowerPointで図形に影の効果をつけると、図形の立体感を向上させ、もっと現実に近づくリアルな効果を実感し、ドキュメントの美感を一層増すことができます。
従って、この記事ではFree Spire.Presentation for Javaを使用してPowerPointの図形に影をつける方法を紹介します。 ちなみに、プリセットされた影の効果以外に、内側の影(InnerShadowEffect)や外側の影(OuterShadowEffect)や輪郭のぼかし(SoftEdgeEffect)などがあります。

JARパッケージのインポート
方法1: Free Spire.Presentation for Javaをダウンロードして解凍したら、libフォルダーのSpire.Presentation.jarパッケージを依存関係としてJavaアプリケーションにインポートします。

方法2: Mavenリポジトリから直接にJARパッケージをインストールしたら、pom.xmlファイルを次のように構成します。

<repositories>
        <repository>
            <id>com.e-iceblue</id>
            <name>e-iceblue</name>
            <url>http://repo.e-iceblue.com/nexus/content/groups/public/</url>
        </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.presentation.free</artifactId>
        <version>3.9.0</version>
    </dependency>
</dependencies>

Javaコード例

import com.spire.presentation.*;
import com.spire.presentation.drawing.FillFormatType;
import com.spire.presentation.drawing.PictureFillType;
import com.spire.presentation.drawing.PresetShadow;

import java.awt.geom.Rectangle2D;
import java.awt.Color;

public class ShapeShadowEffect {

    public static void main(String[] args) throws Exception {

        //Presentationオブジェクトを作成します。
        Presentation ppt = new Presentation();

        //最初目のスライドを取得します。
        ISlide slide = ppt.getSlides().get(0);

        //図形を追加します。
        Rectangle2D rect = new Rectangle2D.Float(120, 80, 180, 150);
        IAutoShape shape = slide.getShapes().appendShape(ShapeType.RECTANGLE,rect);

        //画像を図形に塗りつぶします。
        shape.getFill().setFillType(FillFormatType.PICTURE);
        shape.getFill().getPictureFill().getPicture().setUrl("C:\\Users\\Administrator\\Desktop\\cow.png");
        shape.getFill().getPictureFill().setFillType(PictureFillType.STRETCH);
        shape.getLine().setFillType(FillFormatType.NONE);

        //影の効果を設定します。
        PresetShadow presetShadow = new PresetShadow();
        presetShadow.setPreset(PresetShadowValue.BACK_RIGHT_PERSPECTIVE);
        presetShadow.getColorFormat().setColor(Color.lightGray);

        //図形に影をつけます。
        shape.getEffectDag().setPresetShadowEffect(presetShadow);

        //ドキュメントを保存します。
        ppt.saveToFile("ShapeShadow.pptx", FileFormat.PPTX_2013);
    }
}

実行結果:
shadow.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaで使用されるジェネリクスで使用される型変数、E、Tなどの意味について

Javaのジェネリクスの型変数としてEやTなどが使われていますが、これらのアルファベットの違いは何なのか気になって調べました。

結論から言うと、型変数名も変数名なので予約語をを使わない限り、構文上の意味は変わらない。

ただ、変数名は人間がわかりやすい、意味を推測しやすいものであると良いので、実際に代入される型がなんの型を表すかによって書き分けをしている。

たとえば、Eはelementで配列の要素の型変数、Tはtypeで厳密な指定はなしなど。

通常の変数を決める時、あとから意味を推測しやすいようにするのと同じようにするのと、
あとから見返したときに、なんの型を表すか分かるように型変数を決めるナリ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Thymeleafで独自Dialectを作成・設定して使ってみた

参画する案件の都合もあり、標準のスタンダードダイアレクトだけでは実現不可能な挙動が多数あったので独自で実装することになりました。
そもそもThymeleaf自体新人時代の研修からあまり触れる機会がなく、むしろJSPの方が馴染み深かったのでほぼイチから勉強しつつはじめました。

実際に試行錯誤しながら実装して意図した動作を再現できたりするうちに段々と楽しくなってきたので、備忘録として残しておこうと思います。

そもそもDialectとは?

基本的に使用する代表的なものは以下のように分類されます。

名前 説明
IProcessorDialect 要素や属性を提供するダイアレクト
IExpressionObjectDialect タグ属性値内のEL式で使用できるオブジェクトを提供するダイアレクト

IProcessorDialectはProcessorを登録してタグを実装するものでth:textのような記述方法で使用可能なもので、
IExpressionObjectDialectは#stringsのようにEL式内で使用可能なユーティリティを追加できることができます。

独自Dialectの使用方法・作成

IProcessorDialect

要素や属性のように記述できるDialectです。
IProcessorDialectにはAbstractProcessorDialectという抽象クラスが用意されているため、通常はそちらを継承して実装していきます。
実際の処理を実装するProcessorを別途作成し、AbstractProcessorDialectの実装クラス内で登録して動作するようにします。

例えば日付をyyyy/mm/ddでフォーマットするように作成すると以下のように使用することができます。

■テンプレート上の記述

<span thex:formatdate="${date}"></span>

■実際に出力される要素

<span>2020/01/01</span>

また、以前作成したDialectをscriptタグ内でインラインで記述したところ、Dialectが認識されずハマったことがありました。

<script th:inline="javascript">
    var test =  [# thex:formatdate="${date}" /] ;
    console.log(test);
</script>

AbstractProcessorDialectの実装の中でインラインで記述が認識されるように設定しないと、テンプレート上で認識されないようです。
そのため、JavaScriptもしくはCSSなど使用するケースに合わせてテンプレートモードの設定が必要です。

@Override
public Set<IProcessor> getProcessors(String dialectPrefix) {
  Set<IProcessor> proccessors = new HashSet<>();

  proccessors.add(new SampleProcesssor(TemplateMode.HTML, dialectPrefix));
  proccessors.add(new SampleProcesssor(TemplateMode.JAVASCRIPT, dialectPrefix));
  proccessors.add(new SampleProcesssor(TemplateMode.CSS, dialectPrefix));

  return proccessors;
}

IExpressionObjectDialect

お試しでIExpressionObjectDialectを実装して#sampleとしてEL式内で使用できるユーティリティを作成していきます。
ユーティリティとして追加する名前については、標準提供されているものと重複しないように注意が必要です。

まずExpressionObjectを登録するDialectを実装していきます。
ここではEL式内で使用する際のユーティリティの名前・実際に処理を行うクラスをインタンス生成を行っていきます。

public class SampleDialect extends AbstractDialect implements IExpressionObjectDialect {

    // EL式内で使用する際の名前の定数
    private static final String SAMPLE_DIALECT_NAME = "sample";

    private static final Set<String> EXPRESSION_OBJECT_NAMES = Collections.singleton(SAMPLE_DIALECT_NAME);


    public SampleDialect() {
        super(SAMPLE_DIALECT_NAME);
    }

    @Override
    public IExpressionObjectFactory getExpressionObjectFactory() {
        return new IExpressionObjectFactory() {

            @Override
            public Set<String> getAllExpressionObjectNames() {
                return EXPRESSION_OBJECT_NAMES;
            }

            @Override
            public Object buildObject(IExpressionContext context, String expressionObjectName) {
                if (SAMPLE_DIALECT_NAME.equals(expressionObjectName)) {
                    // ユーティリティとして処理を行うクラスのインスタンス生成
                    return new Sample();
                }
                return null;
            }

            @Override
            public boolean isCacheable(String expressionObjectName) {
                return true;
            }

        };
    }

}

次に実際にテンプレート側から処理を移譲するクラスを作成していきます。
今回は文字列を受け渡し、整形して画面に表示するシンプルな処理で実装します。

public class Sample {

    public String getSampleString(final String str) {
        return "サンプルの文字列「" + str + "」";
    }

}

実際にHTML上で以下のようにEL式内で使用することができるようになります。

■テンプレート上の記述

<span th:text="${#sample.getSampleString('sampleです')}"

■実際に出力される要素

<span>サンプルの文字列「sampleです」</span>

Spring MVC上の設定実装

MVC上で動作できるよう設定クラスにViewResolverの設定を行っていきます。
(Java Configの実装方法についてはこちら)
ここで独自のDialectを登録することができるので、併せて登録してテンプレート上で動作するようにすることが可能です。
(IProcessorDialect・IExpressionObjectDialectどちらも設定方法は基本的に同じです)

// エンコード設定に使用する定数
public static final String CHARACTER_ENCODING = "UTF-8";

// テンプレートが配置されているベースディレクトリパスの定数
private static final String VIEW_LOCATION = "/WEB-INF/views/";


// ThymeleafViewResolverをBean定義する
@Bean
public ThymeleafViewResolver viewResolver() {
    final ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
    thymeleafViewResolver.setTemplateEngine(templateEngine());
    thymeleafViewResolver.setCharacterEncoding(CHARACTER_ENCODING); // レスポンスのエンコーディングを設定する

    return thymeleafViewResolver;
}

// SpringTemplateEngineをBean定義する
@Bean
public SpringTemplateEngine templateEngine() {
    final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver());
    templateEngine.addDialect(new SampleDialect()); // 独自Dialectを登録する

    return templateEngine;
}

// TemplateResolverをBean定義する
@Bean
public AbstractConfigurableTemplateResolver templateResolver() {
    final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
    templateResolver.setPrefix(VIEW_LOCATION); // Thymeleafテンプレートが格納されているベースディレクトリを指定する
    templateResolver.setSuffix(".html"); // Thymeleafテンプレートの拡張子を設定する
    templateResolver.setTemplateMode(TemplateMode.HTML); // 解釈するテンプレートモードを設定する(デフォルト値はHTMLモードだが明示的に設定している)
    templateResolver.setCharacterEncoding(CHARACTER_ENCODING); // テンプレートファイルのエンコーディングを設定する

    return templateResolver;
}

設定実装が完了したら、あとはテンプレートファイルを作成して遷移させることで動作できるようになります。
上記の設定内容はあくまでサンプルなので、適宜環境に合わせて変更する必要があると思います。

まとめ

実際に使ってみるとJSPに比べて使いやすいと思う点がたくさんありました。
独自のDialectを簡単に追加することができるので拡張性が高く、スタンダードダイアレクトと組み合わせることで柔軟に実装することができるのが魅力だと感じました。
個人的にはJSPの独自タグより拡張しやすかったです。

SpringがThymeleafを推奨しているのもあって今後も触れる機会はたくさんありそうなので、さらに知見を増やしていきたいと思っています。(できればfreemakerも…)

参考

https://qiita.com/yoshikawaa/items/aba090f291f69185e6a5

https://macchinetta.github.io/server-guideline-thymeleaf/1.5.1.RELEASE/ja/ArchitectureInDetail/WebApplicationDetail/Thymeleaf.html#id21

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java ](MacOS用)クラスパス設定方法

[Java]についてのお話
クラスパス の設定方法(MacOS)

こんにちは。初心者SEのTakeです。

クラスパス の設定方法について、色々な記事を調べていたのですがなかなか解決することができませんでした。
それで私なりにやってみて解決できた方法について書きたいと思います。

ターミナルを開く。

set CLASSPATH=/Users/ユーザー名/~~~~~~~~

と書けば無事にクラスパスを通すことができるようになりました。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

備忘録No.1「配列内の重複した値を数えて表示」[Java]

[コード]

public static void main(String[] args) {
    // TODO 自動生成されたメソッド・スタブ

    String [] array = {"y","x","x","y","z","y","x","y","z","z"};
    List<String> list = new ArrayList<>(Arrays.asList(array));
    TreeSet<String> ts = new TreeSet<>(list);

    for(String s : ts) {
        int count = 0;
        for(String ss : list) {
            if(s.equals(ss)) {
                count++;
            }
        }
        System.out.println(s + " " + count);
    }
}

[出力結果]
x 3
y 4
z 3

[ポイント]
・出力結果まで重複して表示させないように、コレクションのSetを使った。
・表示する順番をアルファベット順にしたかったので、TreeSetを使った。
・Arrays.asList()で、配列をリストとして返した。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む