возврат объекта Void

113

Как правильно вернуть Voidтип, если он не является примитивом? Например. В настоящее время я использую null, как показано ниже.

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}
Роберт
источник
1
Я пишу интерпретатор для формата файла, используя шаблон интерпретатора, но некоторые выражения не имеют возвращаемых значений
Роберт
2
Невозможно создать экземпляр типа Void, поэтому, если вам действительно нужно вернуть что-то этого типа, null - ваш единственный вариант. Однако вам, вероятно, ни для чего не нужно возвращаемое значение, поэтому null подойдет.
Йорн
да, это тоже была моя логика - просто подумал, есть ли более семантический способ
Роберт
1
Я бы закодировал это так же, как ваш пример. Это хороший подход.
Дэвид Руссель

Ответы:

134

Класс Void - это неустановленный класс-заполнитель для хранения ссылки на объект Class, представляющий ключевое слово Java void.

Таким образом, будет достаточно любого из следующего:

  • параметризация Objectи возврат new Object()илиnull
  • параметризация Voidи возвратnull
  • параметризация с NullObjectвашим

Вы не можете сделать этот метод void, и все остальное возвращает что - то . Поскольку это что-то игнорируется, вы можете вернуть что угодно.

Bozho
источник
2
тогда каков в целом правильный способ достижения возвращаемого типа void?
Роберт
1
Если вы хотите вернуть null как void, вам нужно в некоторых случаях использовать его: (Void) null
Патрик Фавр
return (Void)null;
Alex R
можно ли каким-либо образом отличить (Void) null от null?
Orangle,
13

В Java 8 появился новый класс Optional<T>, который можно использовать в таких случаях. Чтобы использовать его, вы должны немного изменить свой код следующим образом:

interface B<E>{ Optional<E> method(); }

class A implements B<Void>{

    public Optional<Void> method(){
        // do something
        return Optional.empty();
    }
}

Это позволяет вам гарантировать, что вы всегда будете получать ненулевое возвращаемое значение из вашего метода, даже если нечего возвращать. Это особенно эффективно при использовании в сочетании с инструментами, определяющими, когда nullможно или нельзя возвращать, например Eclipse @NonNullи @Nullableаннотации.

Эрик Г. Хагстром
источник
5
Я считаю, что это идет не в том направлении. Лучше возвращать гораздо более ограниченный тип, который гораздо яснее передает смысл. Наличие чего-то, что возвращает an, Optional<Void>не нужно по той же причине, что и вы, вы всегда получаете Optional<Void>пустой объект , поэтому все другие методы бессмысленны. Это противоположно тому, почему следует использовать необязательное значение. Вы используете его, потому что он может иметь или не иметь ценности. Также компилятор не может обеспечить method()правильную реализацию. Это потерпит неудачу во время выполнения: return Optional.of(null).
steinybot 09
3

Если вам просто ничего не нужно в качестве вашего типа, вы можете использовать void. Это можно использовать для реализации функций или действий. Затем вы можете сделать что-то вроде этого:

interface Action<T> {
    public T execute();
}

abstract class VoidAction implements Action<Void> {
    public Void execute() {
        executeInternal();
        return null;
    }

    abstract void executeInternal();
}

Или вы можете опустить абстрактный класс и вернуть значение null в каждом действии, которое не требует возвращаемого значения самостоятельно.

Затем вы можете использовать эти действия следующим образом:

Учитывая метод

private static <T> T executeAction(Action<T> action) {
    return action.execute();
}

Вы можете назвать это как

String result = executeAction(new Action<String>() {
    @Override
    public String execute() {
        //code here
        return "Return me!";
    }
});

или для действия void (обратите внимание, что вы ничего не назначаете результат)

executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});
Йорн
источник
2
чем это отличается от того, что у меня уже есть? он по-прежнему просто возвращает null, как я и предлагал
Роберт
Зачем вам возвращать что-нибудь еще? Я хочу сказать, что вам не нужно возвращаемое значение, поэтому не имеет значения, что вы возвращаете. Я попытался прояснить это своим редактированием.
Йорн
1

Просто ради этого, конечно, есть возможность создать Voidэкземпляр с помощью отражения:

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something

        try {
            Constructor<Void> voidConstructor = Void.class.getDeclaredConstructor();
            voidConstructor.setAccessible(true);
            return voidConstructor.newInstance();
        } catch (Exception ex) {
            // Rethrow, or return null, or whatever.
        }
    }
}

Вы, вероятно, не сделаете этого в продакшене.

кап
источник
0

Не существует универсального типа, который сообщал бы компилятору, что метод ничего не возвращает.

Я считаю, что соглашение заключается в использовании Object при наследовании в качестве параметра типа

ИЛИ

Разместите параметр типа вверх, а затем позвольте пользователям вашего класса создать экземпляр с помощью Object и назначить объект переменной, набранной с использованием подстановочного знака типа ?:

interface B<E>{ E method(); }

class A<T> implements B<T>{

    public T method(){
        // do something
        return null;
    }
}

A<?> a = new A<Object>();
Кристофер Озбек
источник
1
Это соглашение об установке типа возвращаемого значения на void с помощью дженериков - мне это не кажется недействительным?
Роберт
Я считаю, что это правильный путь. Ни один пользователь класса A<?>не сможет использовать возвращаемое значение method().
Christopher Oezbek