Я хочу вернуть два объекта из метода Java, и мне было интересно, что может быть хорошим способом сделать это?
Возможные способы, о которых я могу думать, следующие: вернуть HashMap (поскольку эти два объекта связаны) или вернуть ArrayList объектов Object.
Чтобы быть более точным, я хочу вернуть два объекта: (а) List объектов и (б) их имена, разделенные запятыми.
Я хочу вернуть эти два объекта из одного метода, потому что я не хочу перебирать список объектов, чтобы получить имена, разделенные запятыми (что я могу сделать в том же цикле в этом методе).
Почему-то возврат HashMap не выглядит изящным способом.
Связанный вопрос: stackoverflow.com/questions/53453058/…




Если вы хотите вернуть два объекта, вы обычно хотите вернуть один объект, который вместо этого инкапсулирует два объекта.
Вы можете вернуть список объектов 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>>.
Также: зачем вам возвращать список имен, разделенных запятыми, вместо List<String>? Или еще лучше, верните Map<String,TheObjectType> с ключами, являющимися именами, и значениями объектов (если ваши объекты не имеют указанного порядка, и в этом случае NavigableMap может быть тем, что вам нужно.
Причина возврата списка, разделенного запятыми: Если я не создаю список здесь, мне придется сделать это в вызывающей программе, перебирая объекты (требуется значение CS). Возможно, я без надобности делаю предварительную оптимизацию.
Мне всегда было интересно, почему по этой причине в Java нет класса Pair <T, U>.
Джагмал: да, если единственный rason для возврата списка, разделенного запятыми, это оптимизация, то забудьте об этом.
Это работает только в том случае, если предметы, которые вы хотите вернуть, относятся к одному классу или, по крайней мере, имеют близкого общего предка. Я имею в виду, что использовать Object вместо WhateverTypeYouWant не очень удобно.
@David: Я согласен с тем, что использовать здесь Object не очень удобно, но опять же, возвращать объекты без общего предка (кроме, конечно, Object) тоже не очень удобно. Я бы даже сказал, что это запах кода, если он вам нужен.
Иоахим - я сомневаюсь, что вы это увидите, поскольку сообщение такое старое, но мне интересно, не могли бы вы объяснить, почему вы считаете, что возвращать объекты нескольких типов - это «запах кода». Какие проблемы это вызывает или на какие типы плохого дизайна указывает? Спасибо.
@jrtayloriv: проблема с возвратом объектов разных типов заключается в том, что вы не можете последовательно обрабатывать возвращаемые объекты: либо возвращаемый тип зависит от предоставленного ввода (в этом случае это действительно должны быть два разных метода) или не зависит от него ( в этом случае вы должны вернуть общий базовый класс, который имеет достаточно функций, чтобы быть полезными).
@DavidKoelle Вы имеете в виду что-то вроде двунаправленной карты?
Все возможные решения будут представлять собой кладж (например, объекты-контейнеры, ваша идея HashMap, «множественные возвращаемые значения», реализованные с помощью массивов). Я рекомендую восстановить список, разделенный запятыми, из возвращенного списка. Код станет намного чище.
Я согласен с вами в этом, но если я это сделаю, я закончу цикл дважды (я фактически создаю элементы списка один за другим в существующем методе).
@Jagmal: вы можете повторить цикл дважды, но в большинстве случаев это не имеет значения (см. Ответ штуковин).
Да, не пытайтесь оптимизировать свой код, если в этом нет необходимости. gizmo очень прав насчет этого.
До появления Java 5 я бы согласился, что решение Map не идеально. Это не даст вам проверки типа во время компиляции, поэтому может вызвать проблемы во время выполнения. Однако с Java 5 у нас есть универсальные типы.
Итак, ваш метод может выглядеть так:
public Map<String, MyType> doStuff();
MyType, конечно же, является типом возвращаемого вами объекта.
В принципе, я думаю, что возвращение Map - правильное решение в этом случае, потому что это именно то, что вы хотите вернуть - отображение строки на объект.
Это не сработает, если какие-либо имена совпадают. Список может содержать дубликаты, но карта не может (содержать повторяющиеся ключи).
Конечно. Я делал предположения на основе вопроса - возможно, неоправданно :)
Хотя в данном случае ваше предположение верно, я перехожу к преждевременной оптимизации (чего мне не следует делать).
На мой взгляд, здесь действительно есть три варианта, и решение зависит от контекста. Вы можете реализовать построение имени в методе, который создает список. Это ваш выбор, но я не думаю, что он лучший. Вы создаете связь в методе производителя с методом потребления, который не должен существовать. Другим вызывающим абонентам может не потребоваться дополнительная информация, и вы будете рассчитывать дополнительную информацию для этих абонентов.
В качестве альтернативы вы можете попросить вызывающий метод вычислить имя. Если эта информация нужна только одному вызывающему абоненту, вы можете на этом остановиться. У вас нет лишних зависимостей, и, хотя здесь требуется немного дополнительных вычислений, вы избегаете делать свой метод построения слишком конкретным. Это хороший компромисс.
Наконец, вы можете сделать так, чтобы сам список отвечал за создание имени. Я бы пошел по этому пути, если бы вычисления должны были выполняться более чем одним вызывающим абонентом. Я думаю, что это возлагает ответственность за создание имен с классом, который наиболее тесно связан с самими объектами.
В последнем случае моим решением было бы создать специализированный класс List, который возвращает разделенную запятыми строку с именами содержащихся в нем объектов. Сделайте класс достаточно умным, чтобы он создавал строку имени на лету по мере добавления и удаления объектов. Затем верните экземпляр этого списка и вызовите метод генерации имени по мере необходимости. Хотя может быть почти так же эффективно (и проще) просто отложить вычисление имен до первого вызова метода и затем сохранить его (ленивая загрузка). Если вы добавляете / удаляете объект, вам нужно только удалить вычисленное значение, и оно будет пересчитано при следующем вызове.
В C++ (STL) есть парный класс для объединения двух объектов. В Java Generics парный класс недоступен, хотя для него есть требовать. Однако вы могли бы легко реализовать это самостоятельно.
Однако я согласен с некоторыми другими ответами, что если вам нужно вернуть два или более объекта из метода, было бы лучше инкапсулировать их в класс.
Если вы знаете, что собираетесь вернуть два объекта, вы также можете использовать общую пару:
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 генерируются eclipse.cast в порядке, но кажется не совсем правильным.isInstance.Я обычно использую этот класс в каждой кодовой базе, над которой я работаю. Я бы также добавил: реализацию hashCode / equals и, возможно, статические методы isInstance () и cast ().
Конечно, есть много способов сделать этот класс умнее и удобнее в использовании. Версия выше включает в себя то, что достаточно в одноразовой декларации.
@jamesh: не могли бы вы написать здесь подробно свою пару? Я хотел бы знать, как это выглядит после предоставления «реализации hashCode / equals и, возможно, статических методов isInstance () и cast ()». Спасибо.
@QiangLi - я обычно генерирую хэш-код и методы равенства. Метод экземпляра isInstance принимает два класса и проверяет, являются ли экземпляры a и b экземплярами этих классов. Cast берет пару <?,?> И аккуратно применяет ее к паре <A, B>. Реализации должны быть довольно простыми (подсказка: Class.cast (), Class.isInstance ())
@Jamesh, я был бы очень признателен, если бы вы могли объяснить то, что вы здесь сказали. Может быть, отправили как другой ответ? Я бы, конечно, проголосовал за вас! Я просто не знаю, как сделать то, что вы сказали. Спасибо!
Это очень хорошая реализация Pair. Я бы сделал одно небольшое изменение: добавил сообщение в ClassCastException. В противном случае отладка станет кошмаром, если по какой-то причине это не удастся. (и предупреждения о подавлении rawtypes были бы ненужными, если бы вы выполняли приведение к Pair<?,?> (что работает, потому что вам нужны только методы Object из a и b). Вы не возражаете, если я настрою код?
IMHO, более подходящие имена для полей a и b в Pair - это first и second, поскольку это указывает, что известно об этих полях. С другой стороны, для такого базового класса некоторые люди предпочитают более короткие имена полей, поэтому a и b - неплохой выбор.
Я почти всегда заканчиваю тем, что определяю классы 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.
Обновлено: пример Дэвида Ханака более элегантен, поскольку он избегает определения геттеров и по-прежнему сохраняет объект неизменным.
В качестве альтернативы, в ситуациях, когда я хочу вернуть несколько вещей из метода, я иногда буду использовать механизм обратного вызова вместо контейнера. Это очень хорошо работает в ситуациях, когда я не могу заранее указать, сколько объектов будет сгенерировано.
С вашей конкретной проблемой это будет выглядеть примерно так:
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 ?? наверное, глупый вопрос, но у меня есть фундаментальная путаница!
Почему бы не создать объект WhateverFunctionResult, содержащий ваши результаты, а также - логику, необходимую для синтаксического анализа этих результатов, последующего перебора и т. д. Мне кажется, что либо:
Я вижу, что подобные проблемы возникают снова и снова. Не бойтесь создавать свои собственные классы контейнеров / результатов, которые содержат данные и связанные с ними функции для обработки этого. Если вы просто передаете материал в HashMap или подобном, то вашим клиентам придется разбирать эту карту и просматривать содержимое каждый раз, когда они хотят использовать результаты.
Потому что это PITA - определять класс всякий раз, когда вам нужно вернуть несколько значений, просто потому, что в языке отсутствует эта обычно полезная функция;) А если серьезно, то, что вы предлагаете, очень часто стоит делать.
ПРОЙДИТЕ ХЭШ В МЕТОД И НАСЕЛЕНИЕ ЕГО ......
public void buildResponse (строковые данные, ответ карты);
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]);
}
}
Использование следующего объекта Entry Пример :
public Entry<A,B> methodname(arg)
{
.......
return new AbstractMap.simpleEntry<A,B>(instanceOfA,instanceOfB);
}
В 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);
Однако в объектно-ориентированном языке обычно считается предпочтительным сделать то, что несколько человек уже предлагали за четыре года до этого ответа: сгруппировать два связанных значения в один объект (пару, кортеж или определение настраиваемого класса), а затем получить список этих объекты. Это позволяет избежать необходимости передавать несколько списков. Это становится особенно важным, если нужно передать такую пару (по одному элементу каждого из ваших списков) другим методам для дальнейшей обработки.
@ToolmakerSteve Чтобы уточнить: списки предназначены для того, чтобы иметь ровно по одному элементу каждый и являются лишь средством реализации аналога передачи по указателю. Они не предназначены для сбора нескольких результатов и даже не используются дальше, чем через пару строк после вызова метода.
Если метод, который вы вызываете, является частным или вызывается из одного места, попробуйте
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 Дэвида Ханака не имеет синтаксических преимуществ и ограничен двумя значениями.
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;
Пара имеет преимущество управления типом класса
ИМХО, не идите по этому пути - в декларации слишком мало сказано об ожидаемых возвращаемых значениях. AFAIK, более широко предпочтительнее создавать универсальные классы, которые определяют, сколько параметров возвращается, и тип этих параметров. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4> и т.д. Затем конкретное использование показывает количество и типы параметров Pair<int, String> temp = ... или что-то еще.
Может делать что-то вроде кортежа на динамическом языке (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);
Что касается проблемы с несколькими возвращаемыми значениями в целом, я обычно использую небольшой вспомогательный класс, который обертывает одно возвращаемое значение и передается как параметр методу:
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);
Преимущества (по сравнению с другими предлагаемыми решениями):
Благодарим за решение, которое дает имена и безопасность типа каждому возвращаемому значению, не требуя объявления класса для каждого набора типов возвращаемых значений.
Передайте список вашему методу и заполните его, а затем верните String с именами, например:
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);
Я следовал подходу, аналогичному описанному в других ответах, с несколькими настройками, основанными на моем требовании, в основном я создал следующие классы (на всякий случай, все это 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!");
}
}
Это не совсем ответ на вопрос, но поскольку каждое из приведенных здесь решений имеет некоторые недостатки, я предлагаю попробовать немного реорганизовать код, чтобы вам нужно было вернуть только одно значение.
Случай первый.
Вам нужно что-то внутри и снаружи вашего метода. Почему бы не посчитать его снаружи и не передать в метод?
Вместо:
[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
}
В Apache Commons для этого есть кортеж и тройка:
ImmutablePair<L,R> Неизменяемая пара, состоящая из двух объектов.
элементы.ImmutableTriple<L,M,R> Неизменяемая тройка, состоящая из
три элемента Object.MutablePair<L,R> Изменчивая пара, состоящая из
два элемента Object.MutableTriple<L,M,R> Мутабельный тройной
состоящий из трех элементов Object.Pair<L,R> Пара, состоящая из
два элемента.Triple<L,M,R> Тройка, состоящая из трех элементов.Вы можете использовать любой из следующих способов:
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());
}
Хотя в вашем случае комментарий может быть хорошим вариантом, в Android вы можете использовать Pair. Просто
return new Pair<>(yourList, yourCommaSeparatedValues);
Сделайте это простым и создайте класс для ситуаций с множественными результатами. В этом примере принимается 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;
}
}
Вы можете использовать HashMap<String, Object> следующим образом
public HashMap<String, Object> yourMethod()
{
.... different logic here
HashMap<String, Object> returnHashMap = new HashMap<String, Object>();
returnHashMap.put("objectA", objectAValue);
returnHashMap.put("myString", myStringValue);
returnHashMap.put("myBoolean", myBooleanValue);
return returnHashMap;
}
Затем при вызове метода в другой области вы можете вернуть каждый объект к его исходному типу:
// call the method
HashMap<String, Object> resultMap = yourMethod();
// fetch the results and cast them
ObjectA objectA = (ObjectA) resultMap.get("objectA");
String myString = (String) resultMap.get("myString");
Boolean myBoolean = (Boolean) resultMap.get("myBoolean");
Я заметил, что пока нет ответов без настраиваемого класса, длины n, без приведения и типа, которые возвращали бы несколько значений.
Вот мой ход:
import java.util.Objects;
public final class NTuple<V, T extends NTuple<?, ?>> {
private final V value;
private final T next;
private NTuple(V value, T next) {
this.value = value;
this.next = next;
}
public static <V> NTuple<V, ?> of(V value) {
return new NTuple<>(value, null);
}
public static <V, T extends NTuple<?, ?>> NTuple<V, T> of(V value, T next) {
return new NTuple<>(value, next);
}
public V value() {
return value;
}
public T next() {
return next;
}
public static <V> V unpack0(NTuple<V, ?> tuple) {
return Objects.requireNonNull(tuple, "0").value();
}
public static <V, T extends NTuple<V, ?>> V unpack1(NTuple<?, T> tuple) {
NTuple<?, T> tuple0 = Objects.requireNonNull(tuple, "0");
NTuple<V, ?> tuple1 = Objects.requireNonNull(tuple0.next(), "1");
return tuple1.value();
}
public static <V, T extends NTuple<?, NTuple<V, ?>>> V unpack2(NTuple<?, T> tuple) {
NTuple<?, T> tuple0 = Objects.requireNonNull(tuple, "0");
NTuple<?, NTuple<V, ?>> tuple1 = Objects.requireNonNull(tuple0.next(), "1");
NTuple<V, ?> tuple2 = Objects.requireNonNull(tuple1.next(), "2");
return tuple2.value();
}
}
Пример использования:
public static void main(String[] args) {
// pre-java 10 without lombok - use lombok's var or java 10's var if you can
NTuple<String, NTuple<Integer, NTuple<Integer, ?>>> multiple = wordCount("hello world");
String original = NTuple.unpack0(multiple);
Integer wordCount = NTuple.unpack1(multiple);
Integer characterCount = NTuple.unpack2(multiple);
System.out.println(original + ": " + wordCount + " words " + characterCount + " chars");
}
private static NTuple<String, NTuple<Integer, NTuple<Integer, ?>>> wordCount(String s) {
int nWords = s.split(" ").length;
int nChars = s.length();
return NTuple.of(s, NTuple.of(nWords, NTuple.of(nChars)));
}
Плюсы:
Минусы:
var
Является ли список и CSV-файлы в основном разными представлениями одних и тех же данных? Похоже, что вам нужен объект, в котором у вас есть единственная ссылка на
Listи своего рода справочная таблица.