Лучшая практика для Java-метода, возвращающего несколько значений?

Мне нужен метод нестатического экземпляра для возврата нескольких значений. Для простого примера предположим, что это boolean success и Object obj, но в общем случае их может быть больше, и они могут быть не связаны друг с другом. Можно подумать о нескольких разных способах этого:

Решение 1

private boolean aMethod(int aParam, Object obj) { ...set obj parameter & return value... }

Решение 2

private Pair<Boolean, Object> aMethod(int aParam) { ...set return pair values... }

Решение 3

private Object obj;
...
private boolean aMethod(int aParam) { ...set obj field & return value... }

Решение 4

private class MethodReturn { // Nested class - could be a separate class instead
    boolean success;
    Object obj;
    // ... Getters and setters omitted for brevity
}

private MethodReturn aMethod(int aParam) { ...set return object values... }

Есть ли еще возможности, которые я мог пропустить? И может ли кто-нибудь прокомментировать плюсы и минусы каждого (и в идеале, которые могут быть лучше всего использовать в большинстве случаев)?

Ответ 1

В общем, я бы пошел на четвертый или на карту в зависимости от конкретного случая, но если вам нужно вернуть несколько несвязанных значений, я думаю, что у вас серьезная проблема дизайна (Check https://en.wikipedia.org/wiki/Single_responsibility_principle)

В конкретном случае (после вашего комментария) я определенно поеду с 4-м моделированием Response со всеми обязательными полями. Возможно, вы также можете подтип с ResponseSuccessful и ResponseFailure.

Ответ 2

Решение 5 — обратный вызов

С обратным вызовом вы можете даже вернуть несколько 2-х кортежей:

private void aMethod(int aParam, BiConsumer<Boolean, String> callback) {
    …
    callback.accept(success1, msg1);
    …
    callback.accept(success2, msg2);
    …
}

Использование:

aMethod(42, (success, msg) -> {
    if (!success) {
        log.error(msg);
    }
});

Кроме того, вы можете вернуть композицию (n > 2) -tuple без пользовательского класса — например для 4-х кортежей:

<A, B, C, D> void aMethod(int aParam, BiFunction<A, B, BiConsumer<C, D>> callback) {
    callback.apply(a, b).accept(c, d);
}

aMethod(42, (a, b) -> (c, d) -> log.debug("" + a + b + c + d));

Прокомментировать ваши решения:

  • Решение 1: это неправильная практика для изменения аргументов, более того, String неизменен
  • Решение 2: обычно используемый шаблон, Pair<T,U> или Tuple2<T,U>
  • Решение 3: хрупкое и обескураженное, оно имеет все недостатки полноты состояния (concurrency и т.д.)
  • Решение 4: похожее на # 2, например. class MethodReturn implements Pair<Boolean, String> {}

N.B.: MethodReturn может быть интерфейсом, который вы реализуете "на лету" (в точке возврата), например:

private MethodReturn aMethod(int aParam) {
    …
    return new MethodReturn() {
        @Override
        public Boolean first() { return success; }

        @Override
        public String second() { return msg; }
    };
}

Ответ 3

В моих программах, если возвращаемые объекты логически связаны чем-то, им может потребоваться собственный класс: a boolean и a String могут быть MessageStatus (изменить: я вижу, что это ваш 4-й раствор).
Чтобы дать вам конкретный пример:

public class TurnToken {
/**
 * Number of available Quick Actions
 */
private int quickActionTimes;
/**
 * Number of available Main Actions
 */
private int mainActionTimes;
[...Etcetera with setters and getters]

Этот класс состоит только из двух целых чисел, но он логически представляет то, что можно считать самой сущностью

EDIT: Я случайно отменил первую часть. Если ваши объекты не примитивны, но логически коррелированы, вы можете создать интерфейс для их сбора:

public interface Adjectivable{
//If they have a commong method even better}

и ваш метод

public List<Adjectivable> myMultiReturningMethod{
    List<Adjectivable> theStuffToReturn = new ArrayList<>();
    Etcetera...
}

Ответ 4

Решение 1 не будет работать, поскольку строки в java неизменяемы,

Решение 3, которое вы не всегда можете применить, поскольку вы, например, выполняете результат, вы не сможете запускать свой метод из этого экземпляра, пока вам нужен результат.

Итак, это оставляет нам решения 2 и 4, которые очень похожи. Как и в обоих случаях, вы возвращаете результат, заключенный в пользовательский класс. Если вы думаете, что для вас достаточно Pair, я бы сказал, использую его и перейду с номером решения 2.

Ответ 5

Вы можете использовать перечисление здесь, если результаты исправлены.

public Enum Status {

     OK("OK"),
     CREATED("Created"),
     ACCEPTED("Accepted"),
     NO_CONTENT("No Content"),
     FORBIDDEN("Forbidden"),
     NOT_FOUND("Not Found");

     private final String reason;

     Status(final String reasonPhrase) {
        this.reason = reasonPhrase;
    }
}

 private Status aMethod(int aParam) {
  ................
  return Status.OK;
 }

Ответ 6

Используйте

Object[] aMethod(){ 

//Create and fill an array of object and return it

}

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