Java で C# の out パラメータみたいなことをやってみる

JavaC# の out パラメータみたいなことができないかということを考えてみたので、ざっとまとめてみます。

そもそも、C# の out パラメータって?

C# の out パラメータは、戻り値だけでなく、引数から値を返したいときに使います。

例えば、文字列を数値としてパースした結果を取得したい場合は int.TryParse(str, out value) とすることで、戻り値にパースが成功したかどうかが、引数の value にパース結果が設定されます*1

using System;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("税抜き金額を入力してください: ");
            string str = Console.ReadLine();

            int result;
            if (int.TryParse(str, out result))
            {
                Console.WriteLine("税込金額は {0:F0}円です。", result * 1.08);
            } else {
                Console.WriteLine("数字以外が入力されました。");
            }
        }
    }
}

例外を使わないので、処理がシンプルで高速になります。

Java でやってみる

これと同様のことを Java でやってみます。


まず必要になるのは、Out クラスです。
(値をラップして保持するだけのクラスです)

public class Out<T> {
    private T value;

    public T get() {
        return this.value;
    }
    public void set(T value) {
        this.value = value;
    }
}


次に、文字列を数値にパースして、Out クラスを使って結果を返却するメソッドを作ります*2

import java.util.Objects;

public class Integers {
    /**
     * 文字列を数値に変換します。
     * @param str 変換する対象の文字列
     * @param result 変換結果の数値
     * @return 変換に成功した場合は true, 失敗した場合は false
     */
    public static boolean tryParse(String str, Out<Integer> result) {
        Objects.requireNonNull(str, "str");
        Objects.requireNonNull(result, "result");

        int value = 0;
        for (char c : str.toCharArray()) {
            if (c < '0' || c > '9') {
                return false;
            }

            value *= 10;
            value += c - '0';
        }

        result.set(value);
        return true;
    }
}


これで必要なクラスは出そろいました。
さっそく、これをさっきの C# のコードっぽく使ってみましょう。

import java.util.Scanner;

public class Sample {
    public static void main(String... args) {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("税抜き金額を入力してください: ");
            String str = scanner.nextLine();

            Out<Integer> result = new Out<Integer>();
            if (Integers.tryParse(str, result)) {
                System.out.format("税込金額は %1$.0f円です。", result.get() * 1.08);
            } else {
                System.out.println("数字以外が入力されました。");
            }
        }
    }
}


あんまり Java のコードっぽくないですね…。

まとめ

似てるとかパクったとかいわれますが、JavaC# はやっぱり別物です。
ちゃんと Java のコードっぽく書くのであれば、戻り値を Optional とするのがいいんじゃないかと思います。

*1:パースに失敗した場合、戻り値は false になり、value には int のデフォルト値 0 が設定されます

*2:今回は処理をシンプルにするため、符号を考慮せず [0-9]* だけが入力されている場合にパース成功としています。