Как множественные значения возвращаются в Java?

11

Иногда вы хотите вернуть несколько значений из функции. Как это обычно делается в Java?

Один из вариантов - использовать массив, например, этот фрагмент Python, который возвращает список или кортеж:

value, success = read_unreliably()
if success:
    print value

Другой вариант - вернуть хеш / dict, как в следующем примере JavaScript:

var result = readUnreliably()
if (result.success) {
    alert(value);
}

Еще один - создать пользовательский объект именно для этой цели, например, в следующем примере Java:

ReadUnreliablyResult result = readUnreliably()
if (result.getSuccess()) {
    System.out.println(result.getValue());
}

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

Майк М. Лин
источник
Действительно ли "настоящие" Java-люди сталкиваются с проблемой использования публичных методов получения и установки, чтобы скрыть поля в таких маленьких внутренних классах? Просто любопытно.
Крис Фармер
3
Да, большинство делает. Поскольку многие фреймворки ожидают стандарт JavaBean, вы можете сожалеть об отсутствии геттеров и сеттеров. В любом случае ваша IDE сгенерирует их для вас.
Эрик Уилсон
3
Или вы можете просто оставить их, основываясь на принципе ЯГНИ. Но это не так часто, как можно было бы ожидать.
MatrixFrog
@FarmBoy: Полагаю, я понимаю, что такое bean-компоненты и тому подобное, но OP подразумевает, что это просто одноразовый класс, предназначенный для возврата нескольких значений.
Крис Фармер
@ChrisFarmer Я думаю, что в этом контексте я никогда не видел, чтобы «настоящий» программист на Java создавал класс для этой цели.
Эрик Уилсон

Ответы:

26

Как это обычно делается в Java?

Больно.

Один из вариантов - использовать массив, например, этот фрагмент Python, который возвращает список или кортеж ...

Другой вариант - вернуть хеш / dict, как в этом примере JavaScript ...

Эти методы не работают в Java; значения должны быть понижены от объекта.

Еще один - создать пользовательский объект именно для этой цели, как в примере с Java ...

Это наиболее часто, но создавать все эти маленькие классы утомительно. В C ++ обычно используется std :: pair, но в Java это обычно не делается.

С Lombok довольно легко создавать небольшие пользовательские объекты:

@RequiredArgsConstructor
public class X {
  private final boolean status;
  private final byte[] data;

}

Кевин Клайн
источник
10
"Как это обычно делается в Java?" «Больно» . LOL, как разработчик Java, я должен +1 вам за это
TheLQ
Использование компактного неизменяемого структурно-подобного класса не так уж больно ... Это действительно похоже на написание структуры C ...
Гийом
1
@Guillaume - конечно, но все эти мелочи складываются во времени и пространстве. Я не знаю, почему сообщество Java не приняло стандартный набор обобщений, таких как "class Pair <T1, T2> {public T1 first; public T2 second; ...}"; в современных языках вы просто «вернуть a, b»; и затем напишите «x, y = f ()»;
Кевин Клайн
1
Я уверен, что некоторые «древние» языки тоже могут это делать :) ИМХО Я обнаружил, что множественные возвращаемые значения могут привести к полному беспорядку, и если вам нужно добавить другие возвращаемые поля, вам просто нужно обновить свою структуру как класс без измените подпись вашего метода.
Гийом
1
Что "больно". меня сильно поразило, да, это именно то, что я чувствую как разработчик Java, когда сталкиваюсь с подобными ситуациями.
artjom
13

Да, так , чтобы создать struct/ tuple/ recordв Java является создание класса. Если это только для внутреннего использования, я предпочитаю использовать небольшой неизменяемый структурный класс с открытыми полями.

Примеры:

public class Unreliably {
    public final boolean success;
    public final int value;
    public Unreliably(boolean success, int value) {
        this.success = success; this.value = value;
    }
}

Это гораздо проще сделать в Scala:

case class Unreliably(success: Boolean, value: Int)
Jonas
источник
8
На самом деле, в Scala вы, скорее всего, просто вернете a Tuple2[Boolean, Int]. Хотя в этом конкретном примере вы бы вернули Option[Int].
Йорг Миттаг
2
Таким образом, это отвечает на вопрос Криса Фармера (в комментариях Q), что настоящие Java-люди не обязательно создают геттеры и сеттеры для маленьких внутренних классов. Вы "настоящий" Java-человек, верно?
Майк М. Лин
2
В других новостях нет настоящих шотландцев.
Джозеф Вайсман
5

Для примера, который вы привели, выдача исключения будет самым стандартным способом его обработки:

try {
    result = readUnreliably();
    System.out.println(result);
} (catch IOException e) {
    System.out.println("Could not read file");
}

Более того, если вы стремитесь иметь функции, которые «делают одно», функция возврата нескольких значений становится менее необходимой, хотя иногда и удобной.

Эрик Уилсон
источник
4

У нас есть универсальный класс Pair, который может хранить один экземпляр A и один экземпляр B. Вероятно, вы можете создать Triplet или Quadruplet таким же образом.

public class Pair<A, B>
{
    ...
}
Рака
источник
1
это делает для некоторого ДЕЙСТВИТЕЛЬНО нечитаемого кода все же. если метод возвращает Pair<String, Integer>, что это значит? что представляют эти значения? Вы не можете знать, не читая реализацию метода.
Сара
1

В Java ваша функция будет возвращать объект (или, возможно, null в случае сбоя). Таким образом, несколько частей данных могут быть возвращены.

Скотт К Уилсон
источник
1

В Java нет явного способа вернуть несколько переменных, однако есть несколько подходов:

  1. Во-первых, идти по пути массива. Это действительно работает, только если у вас все данные одного типа или вы можете временно преобразовать их в один тип.
  2. Второй способ - создать класс с целью передачи нескольких типов переменных. В моей работе мы называем их DTO или объектами передачи данных.

источник