Как вернуть несколько объектов из метода Java?


173

Я хочу вернуть два объекта из метода Java, и мне было интересно, что может быть хорошим способом сделать это?

Возможные пути я могу думать о том, являются: Вернуть HashMap(поскольку эти два объекта связаны) или возвращать ArrayListиз Objectобъектов.

Чтобы быть более точным, два объекта, которые я хочу вернуть, являются (а) Listобъектами и (б) разделенными запятыми именами одного и того же.

Я хочу вернуть эти два объекта из одного метода, потому что я не хочу перебирать список объектов, чтобы получить имена через запятую (что я могу сделать в том же цикле в этом методе).

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


1
Являются ли Список и CSV в основном разными представлениями одних и тех же данных? Похоже, что вам нужен объект, где у вас есть одна Listссылка и своего рода таблица поиска.
Джеймс П.

Ответы:


128

Если вы хотите вернуть два объекта, вы обычно хотите вернуть один объект, который вместо этого инкапсулирует два объекта.

Вы можете вернуть список NamedObjectобъектов следующим образом:

public class NamedObject<T> {
  public final String name;
  public final T object;

  public NamedObject(String name, T object) {
    this.name = name;
    this.object = object;
  }
}

Тогда вы можете легко вернуть List<NamedObject<WhateverTypeYouWant>>.

Также: Почему вы хотите вернуть список имен через запятую вместо a List<String>? Или, еще лучше, вернуть a Map<String,TheObjectType>с ключами, являющимися именами и значениями объектов (если ваши объекты не имеют заданный порядок, в этом случае a NavigableMapможет быть тем, что вы хотите.


Причина возврата списка, разделенного запятыми, заключается в следующем: если я не создаю этот список здесь, я должен был бы сделать это в вызывающей программе, просматривая объекты (требуется значение CS). Возможно, я предварительно оптимизирую без необходимости.
Джагмал

2
Мне всегда было интересно, почему в Java нет класса Pair <T, U> по этой причине.
Дэвид Коэль

Джагмал: да, если единственная причина возврата списка, разделенного запятыми, - это оптимизация, то забудьте об этом.
Иоахим Зауэр

Это хорошо работает, только если предметы, которые вы хотите вернуть, принадлежат к одному классу или, по крайней мере, имеют близкого общего предка. Я имею в виду, что использование Object вместо WhitherTypeYouWant не очень аккуратно.
Дэвид Ханак

@ Дэвид: Я согласен, что использование Object здесь не очень аккуратно, но опять же возвращать объекты без какого-либо общего предка (кроме Object, конечно) также не очень аккуратно. Я бы даже сказал, что это запах кода, если вам это нужно.
Иоахим Зауэр

69

Если вы знаете, что собираетесь вернуть два объекта, вы также можете использовать общую пару:

public class Pair<A,B> {
    public final A a;
    public final B b;

    public Pair(A a, B b) {
        this.a = a;
        this.b = b;
    }
};

Отредактируйте более полностью сформированную реализацию вышеупомянутого:

package util;

public class Pair<A,B> {

    public static <P, Q> Pair<P, Q> makePair(P p, Q q) {
        return new Pair<P, Q>(p, q);
    }

    public final A a;
    public final B b;

    public Pair(A a, B b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((a == null) ? 0 : a.hashCode());
        result = prime * result + ((b == null) ? 0 : b.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        @SuppressWarnings("rawtypes")
        Pair other = (Pair) obj;
        if (a == null) {
            if (other.a != null) {
                return false;
            }
        } else if (!a.equals(other.a)) {
            return false;
        }
        if (b == null) {
            if (other.b != null) {
                return false;
            }
        } else if (!b.equals(other.b)) {
            return false;
        }
        return true;
    }

    public boolean isInstance(Class<?> classA, Class<?> classB) {
        return classA.isInstance(a) && classB.isInstance(b);
    }

    @SuppressWarnings("unchecked")
    public static <P, Q> Pair<P, Q> cast(Pair<?, ?> pair, Class<P> pClass, Class<Q> qClass) {

        if (pair.isInstance(pClass, qClass)) {
            return (Pair<P, Q>) pair;
        }

        throw new ClassCastException();

    }

}

Примечания, в основном о ржавчине с Java и дженерики:

  • оба aи bнеизменны.
  • makePairСтатический метод помогает вам с типизацией котельной пластины, что сделает бриллиантовый оператор в Java 7 менее раздражающим. Есть некоторая работа, чтобы сделать этот действительно хороший re: generics, но теперь все должно быть в порядке. (см. PECS)
  • hashcodeи equalsгенерируются затмением.
  • приведение времени компиляции в castметоде в порядке, но не совсем правильно.
  • Я не уверен isInstance, нужны ли подстановочные знаки в .
  • Я только что написал это в ответ на комментарии, только в целях иллюстрации.

У меня обычно этот класс стучится в каждой кодовой базе, над которой я работаю. Я бы также добавил: реализацию hashCode / equals и, возможно, статические методы isInstance () и cast ().
Джамеш

Конечно, есть много способов сделать этот класс умнее и удобнее в использовании. Версия выше включает в себя то, что достаточно в однократной декларации.
Дэвид Ханак

@jamesh: ты не против написать свою пару здесь? Я хотел бы знать, как это выглядит после предоставления «реализации hashCode / equals и, возможно, статических методов isInstance () и cast ()». Спасибо.
Цян Ли

@QiangLi - я обычно генерирую методы хэш-кода и равно. Метод экземпляра isInstance принимает два класса и гарантирует, что экземпляры a & b являются экземплярами этих классов. Cast берет пару <?,?> И осторожно переводит ее в пару <A, B>. Реализации должны быть довольно простыми (подсказка: Class.cast (), Class.isInstance ())
jamesh

2
Это очень хорошая Pairреализация. Одно небольшое изменение, которое я хотел бы сделать: добавить сообщение в ClassCastException. В противном случае отладка становится кошмаром, если по какой-то причине это не удается. (и rawtypes Подавить-предупреждения были бы не нужны , если бы вы бросили на Pair<?,?>(который работает, потому что вам нужно только Objectметоды от aи b) Вы не возражаете , если я настроить код.?
Joachim Sauer

25

Если метод, который вы вызываете, является приватным или вызывается из одного места, попробуйте

return new Object[]{value1, value2};

Звонящий выглядит так:

Object[] temp=myMethod(parameters);
Type1 value1=(Type1)temp[0];  //For code clarity: temp[0] is not descriptive
Type2 value2=(Type2)temp[1];

Пример Pair от David Hanak не имеет синтаксического преимущества и ограничен двумя значениями.

return new Pair<Type1,Type2>(value1, value2);

И абонент выглядит так:

Pair<Type1, Type2> temp=myMethod(parameters);
Type1 value1=temp.a;  //For code clarity: temp.a is not descriptive
Type2 value2=temp.b;

7
У пары есть преимущество контроля типа класса
Hlex

5
ИМХО, не идите этим путем - декларация слишком мало говорит об ожидаемых возвращаемых значениях. AFAIK, более широко предпочтительным является создание универсальных классов, которые указывают, сколько возвращаемых параметров и тип этих параметров. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>И т.д. Затем конкретного использования показывает количество и типы параметров Pair<int, String> temp = ...или любой другой .
ToolmakerSteve

22

Вы можете использовать любой из следующих способов:

private static final int RETURN_COUNT = 2;
private static final int VALUE_A = 0;
private static final int VALUE_B = 1;
private static final String A = "a";
private static final String B = "b";

1) Использование массива

private static String[] methodWithArrayResult() {
    //...
    return new String[]{"valueA", "valueB"};
}

private static void usingArrayResultTest() {
    String[] result = methodWithArrayResult();
    System.out.println();
    System.out.println("A = " + result[VALUE_A]);
    System.out.println("B = " + result[VALUE_B]);
}

2) Использование ArrayList

private static List<String> methodWithListResult() {
    //...
    return Arrays.asList("valueA", "valueB");
}

private static void usingListResultTest() {
    List<String> result = methodWithListResult();
    System.out.println();
    System.out.println("A = " + result.get(VALUE_A));
    System.out.println("B = " + result.get(VALUE_B));
}

3) Использование HashMap

private static Map<String, String> methodWithMapResult() {
    Map<String, String> result = new HashMap<>(RETURN_COUNT);
    result.put(A, "valueA");
    result.put(B, "valueB");
    //...
    return result;
}

private static void usingMapResultTest() {
    Map<String, String> result = methodWithMapResult();
    System.out.println();
    System.out.println("A = " + result.get(A));
    System.out.println("B = " + result.get(B));
}

4) Использование вашего собственного класса контейнера

private static class MyContainer<M,N> {
    private final M first;
    private final N second;

    public MyContainer(M first, N second) {
        this.first = first;
        this.second = second;
    }

    public M getFirst() {
        return first;
    }

    public N getSecond() {
        return second;
    }

    // + hashcode, equals, toString if need
}

private static MyContainer<String, String> methodWithContainerResult() {
    //...
    return new MyContainer("valueA", "valueB");
}

private static void usingContainerResultTest() {
    MyContainer<String, String> result = methodWithContainerResult();
    System.out.println();
    System.out.println("A = " + result.getFirst());
    System.out.println("B = " + result.getSecond());
}

5) Использование AbstractMap.simpleEntry

private static AbstractMap.SimpleEntry<String, String> methodWithAbstractMapSimpleEntryResult() {
    //...
    return new AbstractMap.SimpleEntry<>("valueA", "valueB");
}

private static void usingAbstractMapSimpleResultTest() {
    AbstractMap.SimpleEntry<String, String> result = methodWithAbstractMapSimpleEntryResult();
    System.out.println();
    System.out.println("A = " + result.getKey());
    System.out.println("B = " + result.getValue());
}

6) Использование пара из Apache Commons

private static Pair<String, String> methodWithPairResult() {
    //...
    return new ImmutablePair<>("valueA", "valueB");
}

private static void usingPairResultTest() {
    Pair<String, String> result = methodWithPairResult();
    System.out.println();
    System.out.println("A = " + result.getKey());
    System.out.println("B = " + result.getValue());
}

16

Я почти всегда определяю классы n-Tuple, когда пишу код на Java. Например:

public class Tuple2<T1,T2> {
  private T1 f1;
  private T2 f2;
  public Tuple2(T1 f1, T2 f2) {
    this.f1 = f1; this.f2 = f2;
  }
  public T1 getF1() {return f1;}
  public T2 getF2() {return f2;}
}

Я знаю, что это немного уродливо, но это работает, и вам просто нужно определить типы кортежей один раз. Кортежи - это то, чего на самом деле не хватает Java.

РЕДАКТИРОВАТЬ: пример Дэвида Ханака является более элегантным, поскольку он избегает определения геттеров и по-прежнему сохраняет объект неизменным.


9

До Java 5 я бы согласился с тем, что решение Map не является идеальным. Это не даст вам проверку типа времени компиляции, поэтому может вызвать проблемы во время выполнения. Однако в Java 5 у нас есть универсальные типы.

Итак, ваш метод может выглядеть так:

public Map<String, MyType> doStuff();

MyType, конечно, является типом объекта, который вы возвращаете.

По сути, я думаю, что возвращение Map является правильным решением в этом случае, потому что это именно то, что вы хотите вернуть - отображение строки в объект.


Это не будет работать, если какое-либо из имен сталкивается. Список может содержать дубликаты, но карта не может (содержать дубликаты ключей).
tvanfosson

Конечно. Я делал предположения, основанные на вопросе - возможно, излишне :)
kipz

Хотя в этом случае ваше предположение верно, я иду в область преждевременной оптимизации (что я не должен делать).
Джагмал

6

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

С вашей конкретной проблемой это будет выглядеть примерно так:

public class ResultsConsumer implements ResultsGenerator.ResultsCallback
{
    public void handleResult( String name, Object value )
    {
        ... 
    }
}

public class ResultsGenerator
{
    public interface ResultsCallback
    {
        void handleResult( String aName, Object aValue );
    }

    public void generateResults( ResultsGenerator.ResultsCallback aCallback )
    {
        Object value = null;
        String name = null;

        ...

        aCallback.handleResult( name, value );
    }
}

извините за комментирование очень старого вашего ответа, но как идут обратные вызовы относительно сбора мусора? Я, конечно, не очень хорошо разбираюсь в управлении памятью java, если у вас есть объект Aвызова объекта B.getResult()и B.getResult()вызовы A.finishResult()как a callback, объект Bполучает сборщик мусора или он остается до завершения A? возможно глупый вопрос, но у меня есть фундаментальное замешательство!
wired00

6

У Apache Commons есть кортеж и тройка для этого:

  • ImmutablePair<L,R> Неизменная пара, состоящая из двух элементов Object.
  • ImmutableTriple<L,M,R> Неизменная тройка, состоящая из трех элементов Object.
  • MutablePair<L,R> Изменчивая пара, состоящая из двух элементов Object.
  • MutableTriple<L,M,R> Изменчивая тройка, состоящая из трех элементов Object.
  • Pair<L,R> Пара, состоящая из двух элементов.
  • Triple<L,M,R> Тройка, состоящая из трех элементов.

Источник: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html.



5

Использование следующего объекта Entry Пример:

public Entry<A,B> methodname(arg)
{
.......

return new AbstractMap.simpleEntry<A,B>(instanceOfA,instanceOfB);
}

5

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

public class ReturnParameter<T> {
    private T value;

    public ReturnParameter() { this.value = null; }
    public ReturnParameter(T initialValue) { this.value = initialValue; }

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

(для примитивных типов данных я использую небольшие вариации для непосредственного хранения значения)

Метод, который хочет вернуть несколько значений, будет объявлен следующим образом:

public void methodThatReturnsTwoValues(ReturnParameter<ClassA> nameForFirstValueToReturn, ReturnParameter<ClassB> nameForSecondValueToReturn) {
    //...
    nameForFirstValueToReturn.set("...");
    nameForSecondValueToReturn.set("...");
    //...
}

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

ReturnParameter<ClassA> nameForFirstValue = new ReturnParameter<ClassA>();
ReturnParameter<ClassB> nameForSecondValue = new ReturnParameter<ClassB>();
methodThatReturnsTwoValues(nameForFirstValue, nameForSecondValue);

Преимущества (по сравнению с другими предлагаемыми решениями):

  • Вам не нужно создавать специальное объявление класса для отдельных методов и его возвращаемых типов.
  • Параметры получают имя и, следовательно, их легче различить, глядя на сигнатуру метода
  • Введите безопасность для каждого параметра

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

3

Все возможные решения будут клуджами (такими как объекты-контейнеры, ваша идея HashMap, «множественные возвращаемые значения», реализованные с помощью массивов). Я рекомендую восстановить разделенный запятыми список из возвращенного списка. Код в конечном итоге станет намного чище.


Я согласен с вами в этом, но если я сделаю это, то получу цикл в два раза (на самом деле я создаю элементы списка по одному в существующем методе).
Джагмал

1
@Jagmal: вы можете повторить цикл дважды, но это не имеет значения в большинстве случаев (см. Ответ штуковины).
Иоахим Зауэр

1
Да, не пытайтесь оптимизировать свой код, если вам действительно не нужно. Гизмо очень прав насчет этого.
Бомба

3

Сохраняйте это простым и создайте класс для ситуации с несколькими результатами. В этом примере принимается ArrayList и текст сообщения из базы данныхhelper getInfo.

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

multResult res = mydb.getInfo(); 

В подпрограмме getInfo вы кодируете:

ArrayList<String> list= new ArrayList<String>();
add values to the list...
return new multResult("the message", list);

и определить класс multResult с помощью:

public class multResult {
    public String message; // or create a getter if you don't like public
    public ArrayList<String> list;
    multResult(String m, ArrayList<String> l){
        message = m;
        list= l;
}

}


2

На мой взгляд, здесь действительно три варианта, и решение зависит от контекста. Вы можете выбрать реализацию конструкции имени в методе, который создает список. Это выбор, который вы выбрали, но я не думаю, что он лучший. Вы создаете связь в методе источника с методом потребления, который не должен существовать. Другим абонентам может не потребоваться дополнительная информация, и вы будете рассчитывать дополнительную информацию для этих абонентов.

В качестве альтернативы вы можете заставить вызывающий метод вычислить имя. Если эта информация нужна только одному абоненту, вы можете на этом остановиться. У вас нет дополнительных зависимостей, и, хотя требуется немного дополнительных вычислений, вы избежали слишком специфического метода построения. Это хороший компромисс.

Наконец, вы могли бы сам список быть ответственным за создание имени. Это тот маршрут, по которому я бы пошел, если расчеты должны выполняться несколькими звонящими. Я думаю, что это возлагает ответственность за создание имен с классом, который наиболее тесно связан с самими объектами.

В последнем случае моим решением было бы создать специализированный класс List, который возвращает разделенную запятыми строку с именами объектов, которые он содержит. Сделайте класс достаточно умным, чтобы он создавал строку имени на лету, когда объекты добавляются и удаляются из него. Затем верните экземпляр этого списка и при необходимости вызовите метод генерации имени. Хотя может быть почти так же эффективно (и проще) просто отложить вычисление имен до первого вызова метода и затем сохранить его (отложенная загрузка). Если вы добавляете / удаляете объект, вам нужно только удалить вычисленное значение и пересчитать его при следующем вызове.


2

Может сделать что-то вроде кортежа в динамическом языке (Python)

public class Tuple {
private Object[] multiReturns;

private Tuple(Object... multiReturns) {
    this.multiReturns = multiReturns;
}

public static Tuple _t(Object... multiReturns){
    return new Tuple(multiReturns);
}

public <T> T at(int index, Class<T> someClass) {
    return someClass.cast(multiReturns[index]);
}
}

и использовать как это

public Tuple returnMultiValues(){
   return Tuple._t(new ArrayList(),new HashMap())
}


Tuple t = returnMultiValues();
ArrayList list = t.at(0,ArrayList.class);

2

Я следовал подходу, аналогичному описанному в других ответах, с некоторыми изменениями, основанными на моих требованиях, в основном я создал следующие классы (на всякий случай, все на языке Java):

public class Pair<L, R> {
    final L left;
    final R right;

    public Pair(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public <T> T get(Class<T> param) {
        return (T) (param == this.left.getClass() ? this.left : this.right);
    }

    public static <L, R> Pair<L, R> of(L left, R right) {
        return new Pair<L, R>(left, right);
    }
}

Затем мое требование было простым: в классе репозитория, который достигает БД, для методов Get, которые извлекают данные из БД, мне нужно проверить, не удалось или не получилось, а затем, в случае успеха, мне нужно поиграть с возвращающимся списком. , если не удалось, остановите выполнение и сообщите об ошибке.

Так, например, мои методы такие:

public Pair<ResultMessage, List<Customer>> getCustomers() {
    List<Customer> list = new ArrayList<Customer>();
    try {
    /*
    * Do some work to get the list of Customers from the DB
    * */
    } catch (SQLException e) {
        return Pair.of(
                       new ResultMessage(e.getErrorCode(), e.getMessage()), // Left 
                       null);  // Right
    }
    return Pair.of(
                   new ResultMessage(0, "SUCCESS"), // Left 
                   list); // Right
}

Где ResultMessage - это просто класс с двумя полями (код / ​​сообщение), а Customer - это любой класс с кучей полей, поступающих из БД.

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

void doSomething(){
    Pair<ResultMessage, List<Customer>> customerResult = _repository.getCustomers();
    if (customerResult.get(ResultMessage.class).getCode() == 0) {
        List<Customer> listOfCustomers = customerResult.get(List.class);
        System.out.println("do SOMETHING with the list ;) ");
    }else {
        System.out.println("Raised Error... do nothing!");
    }
}

1

В C ++ (STL) есть парный класс для объединения двух объектов. В Java Generics парный класс недоступен, хотя на него есть спрос . Вы могли бы легко реализовать это самостоятельно, хотя.

Однако я согласен с некоторыми другими ответами, что если вам нужно вернуть два или более объектов из метода, было бы лучше инкапсулировать их в классе.


1

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

  1. Эти объекты результатов тесно связаны между собой / связаны и принадлежат друг другу, или:
  2. они не связаны, и в этом случае ваша функция недостаточно четко определена с точки зрения того, что она пытается сделать (т.е. делать две разные вещи)

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


Потому что PITA нужно определять класс всякий раз, когда вам нужно вернуть несколько значений, просто потому, что в языке отсутствует эта обычно полезная функция;) А если серьезно, то, что вы предлагаете, очень часто стоит делать.
ToolmakerSteve

1
public class MultipleReturnValues {

    public MultipleReturnValues() {
    }

    public static void functionWithSeveralReturnValues(final String[] returnValues) {
        returnValues[0] = "return value 1";
        returnValues[1] = "return value 2";
    }

    public static void main(String[] args) {
        String[] returnValues = new String[2];
        functionWithSeveralReturnValues(returnValues);
        System.out.println("returnValues[0] = " + returnValues[0]);
        System.out.println("returnValues[1] = " + returnValues[1]);
    }

}

1

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

Дело первое.

Вам нужно что-то внутри, а также за пределами вашего метода. Почему бы не вычислить это снаружи и передать это методу?

Вместо того:

[thingA, thingB] = createThings(...);  // just a conceptual syntax of method returning two values, not valid in Java

Пытаться:

thingA = createThingA(...);
thingB = createThingB(thingA, ...);

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


Случай второй.

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

Вместо того:

[thingA, thingB] = createThings(...);  // see above

Пытаться:

thingA = createThingA(...);
thingB = createThingB(...);

Чтобы сделать его более полезным, эти два метода могут иметь общую логику:

public ThingA createThingA(...) {
    doCommonThings(); // common logic
    // create thing A
}
public ThingB createThingB(...) {
    doCommonThings(); // common logic
    // create thing B
}

0

Передайте список своему методу и заполните его, затем верните строку с именами, например так:

public String buildList(List<?> list) {
    list.add(1);
    list.add(2);
    list.add(3);
    return "something,something,something,dark side";
}

Тогда назовите это так:

List<?> values = new ArrayList<?>();
String names = buildList(values);

-2

Я использовал очень простой подход для решения проблем множественных возвратов. Он служит цели и избегает сложности.

Я называю это подходом с разделителем строк

И он эффективен, так как может даже возвращать значения нескольких типов, например, int, double, char, string и т. Д.

В этом подходе мы используем строку, которая вряд ли будет встречаться вообще. Мы называем это разделителем. Этот разделитель будет использоваться для разделения различных значений при использовании в функции

Например, мы получим наш окончательный возврат как (например) разделитель intValue разделитель doubleValue ... И затем, используя эту строку, мы получим всю необходимую информацию, которая также может иметь различные типы.

Следующий код покажет работу этой концепции

Используется разделитель ! @ # И возвращаются 3 значения intVal, doubleVal и stringVal

        public class TestMultipleReturns {

            public static String multipleVals() {

                String result = "";
                String separator = "!@#";


                int intVal = 5;
                // Code to process intVal

                double doubleVal = 3.14;
                // Code to process doubleVal

                String stringVal = "hello";
                // Code to process Int intVal

                result = intVal + separator + doubleVal + separator + stringVal + separator;
                return (result);
            }

            public static void main(String[] args) {

                String res = multipleVals();

                int intVal = Integer.parseInt(res.split("!@#")[0]);
                // Code to process intVal

                double doubleVal = Double.parseDouble(res.split("!@#")[1]);
                // Code to process doubleVal

                String stringVal = res.split("!@#")[2];

                System.out.println(intVal+"\n"+doubleVal+"\n"+stringVal);
            }
        }

ВЫВОД

5
3.14
hello
BUILD SUCCESSFUL (total time: 2 seconds)

3
гогот. Огромный кодовый запах. Разбор вместо использования доступных объектно-ориентированных функций. ИМО, один из худших примеров кодирования, которые я когда-либо видел. Если только вы не описываете ситуацию, когда вам нужно передавать несколько значений между двумя независимыми программами или другим межпроцессным взаимодействием, и каким-то образом отсутствует доступ к приличному механизму для этого (json или другое).
ToolmakerSteve

-4

В C вы могли бы сделать это, передав указатели на заполнители для результатов в качестве аргументов:

void getShoeAndWaistSizes(int *shoeSize, int *waistSize) {
    *shoeSize = 36;
    *waistSize = 45;
}
...
int shoeSize, waistSize;
getShoeAndWaistSize(&shoeSize, &waistSize);
int i = shoeSize + waistSize;

Давайте попробуем нечто подобное, на Java.

void getShoeAndWaistSizes(List<Integer> shoeSize, List<Integer> waistSize) {
    shoeSize.add(36);
    waistSize.add(45);
}
...
List<Integer> shoeSize = new List<>();
List<Integer> waistSize = new List<>();
getShoeAndWaistSizes(shoeSize, waistSize);
int i = shoeSize.get(0) + waistSize.get(0);

1
Однако на языке OO обычно считается предпочтительным делать то, что несколько человек уже предложили за четыре года до ответа: сгруппировать два связанных значения в один объект (пара, кортеж или определение пользовательского класса), а затем получить список этих объекты. Это позволяет избежать необходимости передавать несколько списков. Это становится особенно важным, если необходимо передать такую ​​пару (один элемент каждого из ваших списков) другим методам для дальнейшей обработки.
ToolmakerSteve

@ ToolmakerSteve Чтобы уточнить: списки предназначены для того, чтобы иметь ровно по одному элементу в каждом, и являются лишь средством реализации аналога для передачи по указателю. Они не предназначены для сбора нескольких результатов или даже для использования дальше, чем пара строк после вызова метода.
Адриан Панасюк

-5

ПРОЙДИТЕ ХАШ В МЕТОД И ПОПУЛЯЙТЕ ЕГО ......

public void buildResponse (String data, Map response);

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.