覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。 twitter: @yyoshikaw

Lombok - valでローカル変数の型を省略する

Lombokのlombok.valの利用サンプルです。

https://projectlombok.org/features/val.html

ローカル変数を扱う場合に、通常であれば変数の型を明確に記述する必要がありますが、
Lombokのvalを使うと型を明示的に書かずに済みます。
ちなみにvalの変数はfinalの扱いとなります。

以下にいくつかのサンプルを記載していますが、サンプルコードとともにdelombokの結果も載せています


文字列を受け取る変数をvalにする

右辺で文字列を記述して左辺の変数ではString型を指定せず、valの変数で受け取ることができます。
valで宣言した変数はfinalのため中身の文字列を変更することはできません。

■サンプルコード

val constStr = "final string";

System.out.println("constStrl: " + constStr + ", constStr.getClass(): " + constStr.getClass());

// constStr = "new string";  <-- finalの変数なのでこれはできない

■実行結果

constStrl: final string, constStr.getClass(): class java.lang.String

■実際に生成されているソースコード

val指定のコードは実際には以下のように変換されています。

final java.lang.String constStr = "final string";
System.out.println("constStrl: " + constStr + ", constStr.getClass(): " + constStr.getClass());


ArrayList型の変数をvalにする(右辺に型の情報あり)

Genericsが絡むようなArrayList型のデータもvalの変数で受けとることができます。
一般的にはArrayListで宣言した値をList型で受け取ると思いますが、
valで宣言した変数の右辺がArrayListの場合は変数の型もArrayListになります。

■サンプルコード

// lombok.valを使用したArrayListの生成(左辺の型の記述を省略できる)
val listVal1 = new ArrayList<String>();
listVal1.add("Hello, World 001!");
listVal1.add("Hello, World 002!");

// listVal1.add(100L); ← 型が合わないのでListに登録できない

System.out.println("listVal1: " + listVal1);

// listVal1 = new ArrayList<String>();  <-- finalの変数なのでこれはできない

■実行結果

listVal1: [Hello, World 001!, Hello, World 002!]

■実際に生成されているソースコード

valを指定した変数の型が、ArrayList<String>になっていることが分かります。

final java.util.ArrayList<java.lang.String> listVal1 = new ArrayList<String>();
listVal1.add("Hello, World 001!");
listVal1.add("Hello, World 002!");

System.out.println("listVal1: " + listVal1);


ArrayList型の変数をvalにする(右辺に型の情報なし)

ArrayList型のデータをvalの変数で受けとる際に右辺に型の情報がないと、変数はArrayList<Object>として扱われます

■サンプルコード

// 右辺のダイヤモンド演算子で型を省略した場合はObject型の扱いになり、なんでも登録できる
val listVal2 = new ArrayList<>();
listVal2.add("Data1");
listVal2.add(1234);
listVal2.add(new java.util.Date());

System.out.println("listVal2: " + listVal2);

// listVal2 = new ArrayList<String>();  <-- finalの変数なのでこれはできない

■実行結果

listVal2: [Data1, 1234, Sun Oct 02 20:05:20 JST 2016]

■実際に生成されているソースコード

valを指定した変数の型が、ArrayList<Object>になっていることが分かります。

final java.util.ArrayList<java.lang.Object> listVal2 = new ArrayList<>();
listVal2.add("Data1");
listVal2.add(1234);
listVal2.add(new java.util.Date());

System.out.println("listVal2: " + listVal2);


val + com.google.common.collect.Lists

Guavaで提供されているListsクラスLists#newArrayListで生成した値をvalの変数として受け取ってみます。
サンプルからわかることは、右辺の内容によってvalがどういう型として扱われるか異なってくるということです。

■サンプルコード

val guavaList1 = Lists.newArrayList();
guavaList1.add("Data1");
guavaList1.add(1234);
guavaList1.add(new java.util.Date());

System.out.println("guavaList1: " + guavaList1);


val guavaList2 = Lists.newArrayList("Str1", "Str2", "Str3");
// guavaList2.add(1234);  <-- 型が合わないのでこれはできない

System.out.println("guavaList2: " + guavaList2);

■実行結果

guavaList1: [Data1, 1234, Sun Oct 02 20:05:20 JST 2016]
guavaList2: [Str1, Str2, Str3]

■実際に生成されているソースコード

右辺に型の情報がなければArrayList<Object>の扱いとなり、右辺に型(String)の情報がある場合は、ArrayList<String>となっています

final java.util.ArrayList<java.lang.Object> guavaList1 = Lists.newArrayList();
guavaList1.add("Data1");
guavaList1.add(1234);
guavaList1.add(new java.util.Date());
System.out.println("guavaList1: " + guavaList1);

final java.util.ArrayList<java.lang.String> guavaList2 = Lists.newArrayList("Str1", "Str2", "Str3");
System.out.println("guavaList2: " + guavaList2);


HashMapの値をvalで受け取る

HashMap型のデータもvalの変数で受けとることができます。
右辺の型の複雑さによらず左辺はvalと書くだけでいけます

■サンプルコード

// lombok.valを使用したHashMapの生成(左辺の型の記述を省略できる)
val mapVal = new HashMap<Integer, String>();
mapVal.put(1, "name-A");
mapVal.put(2, "name-B");

System.out.println("mapVal: " + mapVal);

// mapVal = new HashMap<Integer, String>;  <-- finalの変数なのでこれはできない


val mapVal2 = new HashMap<Integer, List<String>>();
ArrayList<String> mapValue = new ArrayList<>();
mapValue.add("value1");
mapValue.add("value2");
mapVal2.put(1, mapValue);

System.out.println("mapVal2: " + mapVal2);

■実行結果

mapVal1: {1=name-A, 2=name-B}
mapVal2: {1=[value1, value2]}

■実際に生成されているソースコード

右辺の型の情報が左辺の変数の型に反映されていることが分かります

final java.util.HashMap<java.lang.Integer, java.lang.String> mapVal1 = new HashMap<Integer, String>();
mapVal1.put(1, "name-A");
mapVal1.put(2, "name-B");

System.out.println("mapVal1: " + mapVal1);


final java.util.HashMap<java.lang.Integer, java.util.List<java.lang.String>> mapVal2 = new HashMap<Integer, List<String>>();
ArrayList<String> mapValue = new ArrayList<>();
mapValue.add("value1");
mapValue.add("value2");
mapVal2.put(1, mapValue);

System.out.println("mapVal2: " + mapVal2);


List#toArrayで変換した値をvalで受け取る

valで宣言したListの値をList#toArrayで配列に変換してその値をvalの変数で受け取ります

■サンプルコード

val strList2 = Arrays.asList("ichiro", "jiro", "hanako");
val strArray = strList2.toArray(new String[strList2.size()]);

System.out.println("strArray: " + Arrays.toString(strArray));

■実行結果

strArray: [ichiro, jiro, hanako]

■実際に生成されているソースコード

List#toArrayの結果を受け取る変数の型がString[]になっていることが分かります

final java.util.List<java.lang.String> strList2 = Arrays.asList("ichiro", "jiro", "hanako");

final java.lang.String[] strArray = strList2.toArray(new String[strList2.size()]);

System.out.println("strArray: " + Arrays.toString(strArray));


LocalDateの値をvalで受け取る

Java8から増えたLocalDateのLocalDate#nowで、現在日付を取得してvalの変数で受け取ります

■サンプルコード

val date1  = LocalDate.now();

System.out.println("date1: " + date1);

■実行結果

date1: 2016-10-02

■実際に生成されているソースコード

結果を受け取る変数の型がLocalDateになっていることが分かります

final java.time.LocalDate date1 = LocalDate.now();

System.out.println("date1: " + date1);


nullをvalで受け取る

nullをvalの変数で受け取ると、Object型での扱いとなります

■サンプルコード

val nullData = null;

System.out.println("nullData: " + nullData);

■実行結果

nullData: null

■実際に生成されているソースコード

nullを受け取る変数の型がObjectとなっていることが分かります

final java.lang.Object nullData = null;

System.out.println("nullData: " + nullData);


Optional型の値をvalで受け取る

java.util.Optionalの値をvalの変数で受け取ります。
Optional#ofで作成する際の型の情報が反映されます。

■サンプルコード

val option1 = Optional.of("data001");

System.out.println("option1: " + option1.get());

■実行結果

option1: data001

■実際に生成されているソースコード

Optionalでラップする値の型がStringになっていることが分かります

final java.util.Optional<java.lang.String> option1 = Optional.of("data001");

System.out.println("option1: " + option1.get());



ソースコードの全体は以下の通りです

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

import com.google.common.collect.Lists;

import lombok.val;

public class ValClient {

    public static void main(String[] args) {
        val constStr = "final string";
        System.out.println("constStrl: " + constStr + ", constStr.getClass(): " + constStr.getClass());
        // constStr = "new string";  <-- finalの変数なのでこれはできない

        // 通常のArrayListの生成(java6の場合)
        final ArrayList<String> listNormal = new ArrayList<String>();
        listNormal.add("Hello, World 1!");
        listNormal.add("Hello, World 2!");
        System.out.println("listNormal: " + listNormal);


        // lombok.valを使用したArrayListの生成(左辺の型の記述を省略できる)
        val listVal1 = new ArrayList<String>();
        listVal1.add("Hello, World 001!");
        listVal1.add("Hello, World 002!");
        // listVal1.add(100L); ← 型が合わないのでListに登録できない
        System.out.println("listVal1: " + listVal1);

        // listVal1 = new ArrayList<String>();  <-- finalの変数なのでこれはできない

        // 右辺のダイヤモンド演算子で型を省略した場合はObject型の扱いになり、なんでも登録できる
        val listVal2 = new ArrayList<>();
        listVal2.add("Data1");
        listVal2.add(1234);
        listVal2.add(new java.util.Date());
        System.out.println("listVal2: " + listVal2);

        // listVal2 = new ArrayList<String>();  <-- finalの変数なのでこれはできない


        // 通常のHashMapの生成(java6の場合)
        final HashMap<Integer, String> mapNormal = new HashMap<Integer, String>();
        mapNormal.put(1, "name-1");
        mapNormal.put(2, "name-2");
        // mapNormal.put("key1", "name-2");  <-- keyの型が合わないので登録できない
        System.out.println("mapNormal: " + mapNormal);

        // lombok.valを使用したHashMapの生成(左辺の型の記述を省略できる)
        val mapVal = new HashMap<Integer, String>();
        mapVal.put(1, "name-A");
        mapVal.put(2, "name-B");
        System.out.println("mapVal1: " + mapVal);

        // mapVal = new HashMap<Integer, String>;  <-- finalの変数なのでこれはできない


        val strList1 = Arrays.asList("abc", "def", "ghi");
        System.out.println("strList1: " + strList1);

        // java.util.ArryList<Object>
        val guavaList1 = Lists.newArrayList();
        guavaList1.add("Data1");
        guavaList1.add(1234);
        guavaList1.add(new java.util.Date());
        System.out.println("guavaList1: " + guavaList1);

        val guavaList2 = Lists.newArrayList("Str1", "Str2", "Str3");
        // guavaList2.add(1234);  <-- 型が合わないのでこれはできない
        System.out.println("guavaList2: " + guavaList2);

        val strArray = guavaList2.toArray(new String[guavaList2.size()]);
        System.out.println("strArray: " + Arrays.toString(strArray));

        val mapVal2 = new HashMap<Integer, List<String>>();
        ArrayList<String> mapValue = new ArrayList<>();
        mapValue.add("value1");
        mapValue.add("value2");
        mapVal2.put(1, mapValue);

        System.out.println("mapVal2: " + mapVal2);

        val date1  = LocalDate.now();
        System.out.println("date1: " + date1);

        val nullData = null;
        System.out.println("nullData: " + nullData);

        val option1 = Optional.of("data001");
        System.out.println("option1: " + option1.get());
    }
}



関連エントリ