LoginSignup
3
4

More than 5 years have passed since last update.

流れるようなインタフェースで例外作成

Posted at

なんでも引数付きコンストラクタでやろうとする例外のインタフェースは使いにくいですよね。
ってお話です。

前提

  • java8以降

問題となる例外

例えば2つ独自フィールドを持つ例外を作る場合


@Getter
public class SampleException extends RuntimeException {

    private String code;

    private String id;

    ...

コンストラクタどんなものを用意するかって話になります。

  • codeが入るパターン
  • idが入るパターン
  • messageが入るパターン
  • causeが入るパターン

これの組み合わせ...って考えてコンストラクタを作り始めるともう大変です。
さらにcodeidmessageは同じ型なのでそれぞれに対してそれしか設定しないコンストラクタを作ることはできません。

    public SampleException(String message, String id, String code) {
        super(message);
        this.id = id;
        this.message = message;
    }

として入らないところにはNullを入れればいい。って思うかもしれませんがスマートじゃないです。
また、コンストラクタが増えてくると使う側が順番を気にしなきゃいけなくて大変です。(ちゃんとjavadocを書いていれば見れば分かりますが、いちいち見なければ分かりません。)
フィールド2つでこのレベルなので、フィールドが増えてったら悲惨です...

流れるようなインタフェースで解決

@Getter
public class SampleException extends RuntimeException {

    private String code;

    private String id;

    private SampleException(String message, Throwable cause) {
        super(message, cause);
    }

    public static class SampleExceptionThrower {

        private String message;

        private Throwable cause;

        private String code;

        private String id;

        private SampleExceptionThrower() {
        }

        public static void call(Consumer<SampleExceptionThrower> consumer) {
            SampleExceptionThrower builder = new SampleExceptionThrower();
            consumer.accept(builder);
            SampleException exception = new SampleException(builder.message, builder.cause);
            exception.code = builder.code;
            exception.id = builder.id;
            throw exception;
        }

        public SampleExceptionThrower setMessage(String message) {
            this.message = message;
            return this;
        }

        public SampleExceptionThrower setCause(Throwable cause) {
            this.cause = cause;
            return this;
        }

        public SampleExceptionThrower setId(String id) {
            this.id = id;
            return this;
        }

        public SampleExceptionThrower setCode(String code) {
            this.code = code;
            return this;
        }

    }

}

Fluent Builderパターンです。こんな風に使えます。

SampleExceptionThrower.call(builder -> builder.setCause(e)
    .setMessage("message").setCode("code"));

すごくすっきり!

あとがき

callっていう命名が気に食わないので誰か何かいい案をください...

3
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4