1. 概要

Java開発者として、私たちは時々[X50X] Void タイプに遭遇し、その目的は何であるか疑問に思ったことがあるかもしれません。

このクイックチュートリアルでは、この特殊なクラスについて学習し、いつどのように使用するか、および可能な場合は使用を避ける方法を確認します。

2. Voidタイプとは

JDK 1.1以降、JavaはVoidタイプを提供します。 その目的は、単にvoid returnタイプをクラスとして表し、クラスを含めることです。 公共の価値。 唯一のコンストラクターがプライベートであるため、インスタンス化できません。

したがって、Void変数に割り当てることができる値はnullのみです。 少し役に立たないように見えるかもしれませんが、このタイプをいつどのように使用するかを見ていきます。

3. 使用法

Voidタイプの使用がおもしろい場合があります。

3.1. 反射

まず、リフレクションを行うときに使用できます。 それはそう、 voidメソッドの戻り型は、クラスを保持するVoid.TYPE変数と一致します。 前述の値

単純なCalculatorクラスを想像してみましょう。

public class Calculator {
    private int result = 0;

    public int add(int number) {
        return result += number;
    }

    public int sub(int number) {
        return result -= number;
    }

    public void clear() {
        result = 0;
    }

    public void print() {
        System.out.println(result);
    }
}

整数を返すメソッドもあれば、何も返さないメソッドもあります。 ここで、結果を返さないすべてのメソッドリフレクションによって取得する必要があるとします。 これは、Void.TYPE変数を使用して実現します。

@Test
void givenCalculator_whenGettingVoidMethodsByReflection_thenOnlyClearAndPrint() {
    Method[] calculatorMethods = Calculator.class.getDeclaredMethods();
    List<Method> calculatorVoidMethods = Arrays.stream(calculatorMethods)
      .filter(method -> method.getReturnType().equals(Void.TYPE))
      .collect(Collectors.toList());

    assertThat(calculatorVoidMethods)
      .allMatch(method -> Arrays.asList("clear", "print").contains(method.getName()));
}

ご覧のとおり、 clear()メソッドと print()メソッドのみが取得されています。

3.2. ジェネリックス

Void タイプの別の使用法は、汎用クラスです。 Callableパラメーターを必要とするメソッドを呼び出しているとしましょう。

public class Defer {
    public static <V> V defer(Callable<V> callable) throws Exception {
        return callable.call();
    }
}

ただし、渡したいCallableは何も返す必要はありません。 したがって、私たちは渡すことができます呼び出し可能

@Test
void givenVoidCallable_whenDiffer_thenReturnNull() throws Exception {
    Callable<Void> callable = new Callable<Void>() {
        @Override
        public Void call() {
            System.out.println("Hello!");
            return null;
        }
    };

    assertThat(Defer.defer(callable)).isNull();
}

上に示したように、 Void戻り型のメソッドから戻るには、nullを返す必要があります。 さらに、ランダムタイプ( 呼び出し可能 ) そして戻るヌルまたはタイプがまったくない( 呼び出し可能) 、 しかし Voidを使用すると、私たちの意図が明確に示されます

このメソッドをラムダに適用することもできます。 実際のところ、Callableはラムダとして記述されている可能性があります。 関数を必要とするメソッドを想像してみましょう。ただし、何も返さない関数を使用します。 次に、Voidを返すようにする必要があります。

public static <T, R> R defer(Function<T, R> function, T arg) {
    return function.apply(arg);
}
@Test
void givenVoidFunction_whenDiffer_thenReturnNull() {
    Function<String, Void> function = s -> {
        System.out.println("Hello " + s + "!");
        return null;
    };

    assertThat(Defer.defer(function, "World")).isNull();
}

4. それを使用しないようにする方法は?

ここで、Voidタイプの使用法をいくつか見てきました。 ただし、最初の使用法がまったく問題ない場合でも、可能であればジェネリックスでのVoidの使用を避けたい場合があります。 実際、結果がなく、 null しか含めることができない戻り型に遭遇するのは、面倒な場合があります。

これらの状況を回避する方法を見ていきます。 まず、Callableパラメーターを使用したメソッドについて考えてみましょう。 Callableの使用を避けるため 、代わりにRunnableパラメーターを使用する別のメソッドを提供する場合があります。

public static void defer(Runnable runnable) {
    runnable.run();
}

したがって、値を返さない Runnable を渡すことができるため、無駄な returnnullを取り除くことができます。

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello!");
    }
};

Defer.defer(runnable);

しかし、 Defer クラスを変更する必要がない場合はどうなるでしょうか? 次に、どちらかに固執することができます呼び出し可能オプションまたは Runnableを取得し、Deferクラスへの呼び出しを延期する別のクラスを作成します

public class MyOwnDefer {
    public static void defer(Runnable runnable) throws Exception {
        Defer.defer(new Callable<Void>() {
            @Override
            public Void call() {
                runnable.run();
                return null;
            }
        });
    }
}

そうすることで、面倒な部分を独自のメソッドにカプセル化し、将来の開発者がよりシンプルなAPIを使用できるようにします。

もちろん、機能でも同じことができます。 この例では、 Function は何も返さないため、代わりにConsumerを使用する別のメソッドを提供できます。

public static <T> void defer(Consumer<T> consumer, T arg) {
    consumer.accept(arg);
}

次に、関数がパラメーターを受け取らない場合はどうなりますか? Runnable を使用するか、独自の機能インターフェイスを作成することができます(それがより明確に思える場合)。

public interface Action {
    void execute();
}

次に、 defer()メソッドを再度オーバーロードします。

public static void defer(Action action) {
    action.execute();
}
Action action = () -> System.out.println("Hello!");

Defer.defer(action);

5. 結論

この短い記事では、Java Voidクラスについて説明しました。 その目的と使い方を見ました。 また、その使用法のいくつかの代替案も学びました。

いつものように、この記事の完全なコードはGitHubにあります。