Як повернути кілька об’єктів з методу Java?


172

Я хочу повернути два об’єкти з методу Java, і мені було цікаво, що може бути хорошим способом зробити це?

Можливі шляхи я можу думати про те, є: Повернути HashMap(оскільки ці два об'єкти пов'язані) або повертати ArrayListз Objectоб'єктів.

Якщо точніше, два об'єкти, які я хочу повернути, - це (а) Listоб'єктів і (b) назви однакових комами.

Я хочу повернути ці два Об'єкти з одного методу, тому що я не хочу повторити список об'єктів, щоб отримати відокремлені комами імена (що я можу зробити в одному циклі в цьому методі).

Так чи інакше, повернення арсеналу HashMapвиглядає не дуже елегантним способом.


1
Чи перелік списків і CSV-файлів відрізняються поглядами одних і тих же даних? Це звучить як те, що вам потрібно - це Об'єкт, де у вас є одна Listдовідка і така собі таблиця пошуку.
Джеймс П.

Питання, пов’язані з цим: stackoverflow.com/questions/53453058/…
Джон Макклайн

Відповіді:


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;
  }
}

Тоді ви можете легко повернути a List<NamedObject<WhateverTypeYouWant>>.

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


Причина повернення списку, розділеного комами, полягає в тому, що: якщо я не створюю тут список, мені доведеться це зробити у абонента, перебираючи об'єкти (потрібне значення CS). Можливо, я попередньо оптимізую зайве.
Ягмал

2
Мені завжди було цікаво, чому Java не має класу Pair <T, U> з цієї причини.
Девід Коелле

Ягмал: так, якщо єдиним расоном для повернення розділеного комою списку є ця оптимізація, то забудьте про це.
Йоахім Зауер

Це добре працює лише в тому випадку, якщо предмети, які ви хочете повернути, є одного класу або принаймні мають близького спільного предка. Я маю на увазі, використання об'єкта замість WickerTypeYouWant не дуже охайне.
Девід Ханак

@David: Я погоджуюся, що використання об'єкта тут не дуже охайне, але потім знову повертати об’єкти без будь-якого спільного предка (крім Об'єкта, звичайно), також не дуже охайно. Я б навіть сказав, що це кодовий запах, якщо вам це потрібно.
Йоахім Зауер

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 зробить менш дратівливим. Існує деяка робота, щоб зробити це справді приємним ре: генерикою, але зараз це повинно бути добре. (пор. PECS)
  • hashcodeі equalsпороджуються затемненням.
  • час мовлення компіляції в castметоді нормально, але здається не зовсім правильним.
  • Я не впевнений, чи потрібні подвійні знаки isInstance.
  • Я щойно написав це у відповідь на коментарі, лише для ілюстрації.

У мене зазвичай цей клас стукає у кожній базі коду, над якою я працюю. Я також додам: хеш-код / ​​еквівалент реалізації та, можливо, статичний метод isInstance () та cast ().
jamesh

Звичайно, існує багато способів зробити цей клас розумнішим та зручнішим у використанні. Версія, що наведена вище, включає те, що достатньо лише в одностронній декларації.
Девід Ханак

@jamesh: Ви не хочете написати тут детально свою пару? Мені хотілося б знати, як це виглядає після надання "хеш-коду / рівності реалізації та, можливо, статичного методу isInstance () та cast ()." Дякую.
Цянь Лі

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

2
Це дуже приємна Pairреалізація. Я хотів би внести одну незначну зміну: додати повідомлення до ClassCastException. Інакше налагодження стає кошмаром, якщо це не вдається з якихось причин. (а попереджувальні попередження-попередження були б непотрібними, якщо ви звернетесь до цього Pair<?,?>(що працює, тому що вам потрібні лише Objectметоди з aі b). Чи не заперечуєте, якщо я підправити код?
Йоахім Зауер

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];

Приклад пари Девіда Ханака не має синтаксичної вигоди і обмежується двома значеннями.

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 справді не вистачає.

EDIT: Приклад Девіда Ханака є більш елегантним, оскільки він дозволяє уникнути визначення геттерів і все ще зберігає об'єкт непорушним.


9

Перед Java 5 я б погодився, що рішення Map не є ідеальним. Це не дасть вам скласти перевірку типу часу, тому це може спричинити проблеми під час виконання. Однак у Java 5 у нас є загальні типи.

Отже, ваш метод може виглядати приблизно так:

public Map<String, MyType> doStuff();

MyType, звичайно, тип об’єкта, який ви повертаєте.

В основному я думаю, що повернення Карти - це правильне рішення в цьому випадку, тому що саме це ви хочете повернути - відображення рядка до об'єкта.


Це не спрацює, якщо будь-яке з імен зіткнеться. Список може містити дублікати, але Карта не може (містити повторювані ключі).
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()як callback, чи об’єкт Bзбирає сміття чи він залишається навколо, поки A не закінчиться ?? певно, дурне питання, але його принципова плутанина у мене є!
wired00

6

Apache Commons має кортеж та потрійність для цього:

  • ImmutablePair<L,R> Незмінна пара, що складається з двох елементів об’єкта.
  • ImmutableTriple<L,M,R> Незмінна трійка, що складається з трьох елементів об’єкта.
  • MutablePair<L,R> Змінна пара, що складається з двох елементів об'єкта.
  • MutableTriple<L,M,R> Змінна трійка, що складається з трьох елементів об’єкта.
  • Pair<L,R> Пара, що складається з двох елементів.
  • Triple<L,M,R> Трійка, що складається з трьох елементів.

Джерело: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html


6

Хоча у вашому випадку коментар може бути хорошим способом, в Android ви можете скористатися Pair . Просто

return new Pair<>(yourList, yourCommaSeparatedValues);

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: ви можете циклічно двічі, але це не має значення більшості часу (див. Відповідь gizmos).
Йоахім Зауер

1
Так, не намагайтеся оптимізувати свій код, якщо вам справді не доведеться. gizmo дуже вірно з цього приводу.
Бомбе

3

Нехай це буде просто і створити клас для ситуації з кількома результатами. Цей приклад приймає список ArrayList та текст повідомлення від помічника бази даних 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);
    }
}

Тоді моя вимога була простою, в класі сховища, що доходить до БД, для методів отримання, ніж отримання даних з БД, мені потрібно перевірити, чи не вдалося це чи вдалося, тоді, якщо вдасться, мені потрібно було грати зі списком, що повертається , якщо не вдалося, зупиніть виконання та повідомте про помилку.

Наприклад, наприклад, мої методи такі:

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 separator doubleValue separator ... І тоді, використовуючи цей рядок, ми отримаємо всю необхідну інформацію, яка також може бути різного типу

Наступний код покаже функціонування цієї концепції

Використовуваний роздільник :! @ # І 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
юк. Величезний кодовий запах. Парсинг замість використання доступних об'єктно-орієнтованих функцій. IMO, один з найгірших прикладів кодування, який я коли-небудь бачив. Якщо ви не описуєте ситуацію, коли вам потрібно передати кілька значень між двома незалежними програмами або іншим міжпроцесорним зв’язком, і якимось чином бракує доступу до гідного механізму для цього (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
Однак мовою ОО, як правило, вважається бажаним робити те, що кілька людей вже запропонували за чотири роки до цієї відповіді: згрупуйте ці два пов’язані значення в один об'єкт (пару, кортеж або визначення спеціального класу), а потім складіть їх список об’єкти. Це дозволяє уникнути необхідності обійти декілька списків. Це стає особливо важливим, якщо потрібно передати таку пару (по одному елементу кожного із ваших списків) іншим методам для подальшої обробки.
ToolmakerSteve

@ToolmakerSteve Для уточнення: списки повинні містити по одному елементу кожен і є лише засобом для впровадження аналога до провідного вказівника. Вони не призначені для збору декількох результатів або навіть використовуються далі, ніж пара рядків після виклику методу.
Адріан Панасюк

-5

ЗАПАДУЙТЕ МАШИНУ МЕТОДУ І НАСЕЛЕНИЙ ЙОГО ......

public void buildResponse (рядкові дані, відповідь на карті);

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.