LoginSignup
3
3

JavaのOptionalとガード節を共存させてみた

Last updated at Posted at 2018-01-29

Java SE 8のOptionalはガード節と相性が悪いのが悩みどころですが、
何とかガード節と共存できないかなと考えて作ってみました。

package com.ikemo3;

import java.util.Optional;

public class Main {

    public static void main(String[] args) {
        System.out.println(Main.sqrt("16"));
        System.out.println(Main.sqrt("-16"));
        System.out.println(Main.sqrt("str"));
    }

    public static String sqrt(String str) {
        return Optionals.of(str, String.class)
                .guard((s) -> toInteger(s), () -> "整数ではない")
                .guard((i) -> sqrt(i), () -> "正の数ではない")
                .get((d) -> String.valueOf(d));
    }

    /**
     * 値が正なら整数にする
     */
    public static Optional<Integer> toInteger(String str) {
        try {
            return Optional.of(Integer.valueOf(str));
        } catch (NumberFormatException e) {
            return Optional.empty();
        }
    }

    /**
     * 値が正なら平方根を取る
     */
    public static Optional<Double> sqrt(int i) {
        if (i >= 0) {
            return Optional.of(Math.sqrt(i));
        } else {
            return Optional.empty();
        }
    }
}

出力結果は以下のようになります。

4.0
正の数ではない
整数ではない

呼び出し方はこんな感じです。
だいたいガード節っぽく見えるかなと。

    public static String sqrt(String str) {
        return Optionals.of(str, String.class)
                .guard((s) -> toInteger(s), () -> "整数ではない")
                .guard((i) -> sqrt(i), () -> "正の数ではない")
                .get((d) -> String.valueOf(d));
    }

クラスの実装は次の通り。

package com.ikemo3;

import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

public class Optionals<IN, RET> {
    private final IN value;
    private final RET elseValue;
    private final Class<RET> clazz;

    public static <IN, OUT> Optionals<IN, OUT> of(IN value, Class<OUT> clazz) {
        return new Optionals(value, clazz);
    }

    private Optionals(IN value, Class<RET> clazz) {
        this.value = value;
        this.clazz = clazz;
        this.elseValue = null;
    }

    private Optionals(RET elseValue) {
        this.value = null;
        this.clazz = null;
        this.elseValue = elseValue;
    }

    public <OUT> Optionals<OUT, RET> guard(Function<IN, Optional<OUT>> func, Supplier<RET> elseValue) {
        if (this.elseValue != null) {
            return new Optionals(this.elseValue);
        }

        Optional<OUT> result = func.apply(this.value);
        if (result.isPresent()) {
            return Optionals.of(result.get(), this.clazz);
        } else {
            return new Optionals(elseValue.get());
        }
    }

    public RET get(Function<IN, RET> func) {
        if (this.elseValue != null) {
            return this.elseValue;
        } else {
            return func.apply(this.value);
        }
    }
}
3
3
2

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
3