Рубрики
Без рубрики

Как вернуть Несколько Значений Из Метода Java

Некоторые языки программирования предоставляют простые способы возврата нескольких значений из метода. В Java есть несколько подобных опций, в зависимости от типов.

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы изучим различные способы возврата нескольких значений из метода Java.

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

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

2. Использование массивов

Массивы могут использоваться для возврата как примитивных, так и ссылочных типов данных .

Например, следующий метод getCoordinates возвращает массив из двух double значений:

double[] getCoordinatesDoubleArray() {
  
    double[] coordinates = new double[2];

    coordinates[0] = 10;
    coordinates[1] = 12.5;
  
    return coordinates;
}

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

Number[] getCoordinatesNumberArray() {
  
    Number[] coordinates = new Number[2];

    coordinates[0] = 10;   // Integer
    coordinates[1] = 12.5; // Double
  
    return coordinates;
}

Здесь мы определили координаты массив типа Число , потому что это общий класс между Целочисленными и двойными элементами.

3. Использование коллекций

С помощью общих коллекций Java , мы можем возвращать несколько значений общего типа .

Платформа коллекций имеет широкий спектр классов и интерфейсов. Однако в этом разделе мы ограничимся обсуждением интерфейсов List и Map .

3.1. Возврат значений аналогичного типа в списке

Для начала давайте перепишем предыдущий пример массива с помощью List :

List getCoordinatesList() {
  
    List coordinates = new ArrayList<>();
  
    coordinates.add(10);  // Integer
    coordinates.add(12.5);  // Double
  
    return coordinates;
}

Как и Number[] , коллекция List содержит последовательность элементов смешанного типа одного и того же общего типа.

3.2. Возврат именованных значений на карте

Если мы хотим назвать каждую запись в нашей коллекции, вместо этого можно использовать Map :

Map getCoordinatesMap() {
  
    Map coordinates = new HashMap<>();
  
    coordinates.put("longitude", 10);
    coordinates.put("latitude", 12.5);
  
    return coordinates;
}

Пользователи метода get Coordinates Map могут использовать ключи ” долгота” или ” широта” с помощью метода Map#get для получения соответствующего значения.

4. Использование Классов Контейнеров

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

Например, следующий класс Координаты имеет два разных типа данных: double и String :

public class Coordinates {
  
    private double longitude;
    private double latitude;
    private String placeName;
  
    public Coordinates(double longitude, double latitude, String placeName) {
  
        this.longitude = longitude;
        this.latitude = latitude;
        this.placeName = placeName;
    }
  
    // getters and setters
}

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

Следующим шагом является создание и возврат экземпляра Координат :

Coordinates getCoordinates() {
  
    double longitude = 10;
    double latitude = 12.5;
    String placeName = "home";
  
    return new Coordinates(longitude, latitude, placeName);
}

Следует отметить, что рекомендуется создавать классы данных, такие как Координаты |/неизменяемые . Таким образом, мы создаем простые, потокобезопасные, общие объекты.

5. Использование Кортежей

Как и контейнеры, кортежи хранят поля разных типов. Однако они отличаются тем, что не зависят от конкретного приложения .

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

Кортеж может содержать любое количество полей и часто называется Кортеж n, где n – количество полей. Например, Tuple2-это кортеж из двух полей, Tuple3-кортеж из трех полей и так далее.

Чтобы продемонстрировать важность кортежей, рассмотрим следующий пример. Предположим, что мы хотим найти расстояние между точкой Координат и всеми другими точками внутри списка <Координаты> . Затем нам нужно вернуть этот самый удаленный объект координат вместе с расстоянием.

Давайте сначала создадим общий кортеж из двух полей:

public class Tuple2 {

    private K first;
    private V second;
  
    public Tuple2(K first, V second){
        this.first = first;
        this.second = second;
    }

    // getters and setters
}

Далее, давайте реализуем нашу логику и используем экземпляр Tuple2<Координаты, Двойной> , чтобы обернуть результаты:

Tuple2 getMostDistantPoint(List coordinatesList, 
                                                       Coordinates target) {

    return coordinatesList.stream()
      .map(coor -> new Tuple2<>(coor, coor.calculateDistance(target)))
      .max((d1, d2) -> Double.compare(d1.getSecond(), d2.getSecond())) // compare distances
      .get();
}

Использование Tuple2 Double> в предыдущем примере избавило нас от создания отдельного контейнерного класса для одноразового использования с этим конкретным методом . Double>

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

6. Сторонние библиотеки

Некоторые сторонние библиотеки реализовали неизменяемый тип Pair или Triple . Apache Commons Lang и javatuples являются примерами. Как только у нас есть эти библиотеки в качестве зависимостей в нашем приложении, мы можем напрямую использовать типы Pair или Triple , предоставляемые библиотеками, вместо того, чтобы создавать их самостоятельно.

Давайте рассмотрим пример использования Apache Commons Lang для возврата объекта Pair или Triple .

Прежде чем мы сделаем следующий шаг, давайте добавим зависимость commons-lang3 в ваш pom.xml:


    org.apache.commons
    commons-lang3
    3.11

6.1. Неизменяемая пара из Apache Commons Lang

Тип ImmutablePair из Apache Commons Lang-это именно то, что нам нужно: неизменяемый тип, использование которого является простым.

Он содержит два поля: left и right . Давайте посмотрим, как сделать так, чтобы наш метод get Most Distant Point возвращал объект типа ImmutablePair :

ImmutablePair getMostDistantPoint(
  List coordinatesList, Coordinates target) {
    return coordinatesList.stream()
      .map(coordinates -> ImmutablePair.of(coordinates, coordinates.calculateDistance(target)))
      .max(Comparator.comparingDouble(Pair::getRight))
      .get();
}

6.2. Неизменяемый пример из Apache Commons Lang

ImmutableTriple очень похож на ImmutablePair . Единственное различие заключается в том, что, как следует из названия, ImmutableTriple содержит три поля: left , middle, и right.

Теперь давайте добавим новый метод к нашему вычислению координат, чтобы показать, как использовать тип ImmutableTriple .

Мы собираемся пройти через все точки в List<Координаты> , чтобы узнать min , avg, и max расстояния до заданной целевой точки.

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

ImmutableTriple getMinAvgMaxTriple(
  List coordinatesList, Coordinates target) {
    List distanceList = coordinatesList.stream()
      .map(coordinates -> coordinates.calculateDistance(target))
      .collect(Collectors.toList());
    Double minDistance = distanceList.stream().mapToDouble(Double::doubleValue).min().getAsDouble();
    Double avgDistance = distanceList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0D);
    Double maxDistance = distanceList.stream().mapToDouble(Double::doubleValue).max().getAsDouble();

    return ImmutableTriple.of(minDistance, avgDistance, maxDistance);
}

7. Заключение

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

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

Мы также узнали, что некоторые сторонние библиотеки реализовали парные и тройные типы, и увидели несколько примеров из библиотеки Apache Commons Lang.

Как обычно, исходный код этой статьи доступен на GitHub .