読者です 読者をやめる 読者になる 読者になる

せてぃーずノート

Javaのイベント参加レポートとかを書いたりします。

lambdaでデバッグ、試してみた。

テストパターン

とりあえずパターンは4つ。

  • 無名インナークラス
  • lambdaでベタ書き
  • lambdaからメソッド呼び出し
  • lambdaから静的メソッド呼び出し

とりあえずシナリオはこんな感じ。
「乱数を作ってそれが奇数か偶数かを判定する処理を書いたタカシ君。
でも、本当にその処理が正しいか、デバッグでLongの数値を覗いてみたい。」

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;
import org.junit.Test;

/**
 *
 * @author setys
 */
public class DebugTest {

    public DebugTest() {
    }


    @Test
    public void lambda内で分岐() {
        List<Long> longList = makeList();
        longList.forEach(l -> {
            long mod = l % 2;
            if (mod == 0) {      //  ここにブレークポイント
                System.out.println("ぐうすう!");
            } else {
                System.out.println("きすー!");
            }
        });
    }

    @Test
    public void インナークラスで分岐() {
        List<Long> longList = makeList();
        longList.forEach(new Consumer<Long>() {

            public void accept(Long l) {
                long mod = l % 2;
                if (mod == 0) {        //  ここにブレークポイント
                    System.out.println("ぐうすう!");
                } else {
                    System.out.println("きすー!");
                }
            }
        });
    }

    @Test
    public void メソッド呼び出し() {
        List<Long> longList = makeList();
        longList.forEach(l
                -> printValue(l)
                );
    }

    @Test
    public void 静的メソッド呼び出し() {
        List<Long> longList = makeList();
        longList.forEach(l -> printStatic(l)
                );
    }

    /**
     * テスト用に乱数作ってリストを返す。
     *
     * @return 乱数入りリスト
     */
    private List<Long> makeList() {
        List<Long> longList = new ArrayList<>();
        longList.add(ThreadLocalRandom.current().nextLong());
        longList.add(ThreadLocalRandom.current().nextLong());
        longList.add(ThreadLocalRandom.current().nextLong());
        return longList;
    }

    /**
     * メソッド呼び出しパターン用メソッド
     */
    private void printValue(long mod) {
        if (mod == 0) {     //  ここにブレークポイント
            System.out.println("ぐうすう!");
        } else {
            System.out.println("きすー!");
        }
    }

    /**
     * メソッド呼び出しパターン用静的メソッド
     */
    private static void printStatic(long mod) {
        if (mod == 0) {      //  ここにブレークポイント
            System.out.println("ぐうすう!");
        } else {
            System.out.println("きすー!");
        }
    }
}

結果

lambdaで直接記述(一番上のケース)以外はデバッグで変数の値を確認可能
lambdaの場合はデバッグで止まるものの、変数の中を確認することはできなかった。

まだまだJava8は開発中であり、変わっていくと思うけど、もしこの仕様のままだとlambdaを多用しすぎてデバッグできない問題が起こるかも。
まぁ、メソッド呼んであげたり、デバッガ使わないでトレースする仕組みを入れておけばいいと思いますけど。

lambdaがトレースできないわけ

昨日も書いたけど、きっとこんなかんじだからだと思う

  • 実行時にクラスが生成されている
    • 生成されたクラスにデバッグ情報が入っていない
  • invokeDynamicで呼び出している
    • invokeDynamicの仕組み自体よくわかっていないですけど、呼び出しの手段であるのであまり関係ない?