Cách trả lại nhiều giá trị từ một phương pháp Java

1. Khái quát chung

Trong hướng dẫn này, chúng ta sẽ tìm hiểu các cách khác nhau để trả về nhiều giá trị từ một phương thức Java.

Đầu tiên, chúng tôi sẽ trả về mảng và bộ sưu tập. Sau đó, chúng tôi sẽ trình bày cách sử dụng các lớp vùng chứa cho dữ liệu phức tạp và tìm hiểu cách tạo các lớp tuple chung.

Cuối cùng, chúng ta sẽ xem các ví dụ về cách sử dụng thư viện của bên thứ ba để trả về nhiều giá trị.

2. Sử dụng Mảng

Mảng có thể được sử dụng để trả về cả kiểu dữ liệu nguyên thủy và tham chiếu .

Ví dụ, phương thức getCoferences sau đây trả về một mảng gồm hai giá trị kép :

double[] getCoordinatesDoubleArray() { double[] coordinates = new double[2]; coordinates[0] = 10; coordinates[1] = 12.5; return coordinates; }

Nếu chúng ta muốn trả về một mảng có các kiểu tham chiếu khác nhau, chúng ta có thể sử dụng kiểu mẹ chung làm kiểu của mảng :

Number[] getCoordinatesNumberArray() { Number[] coordinates = new Number[2]; coordinates[0] = 10; // Integer coordinates[1] = 12.5; // Double return coordinates; }

Ở đây chúng ta đã xác định mảng tọa độ kiểu Number vì nó là lớp chung giữa các phần tử IntegerDouble .

3. Sử dụng Bộ sưu tập

Với các tập hợp Java chung, chúng ta có thể trả về nhiều giá trị của một kiểu chung .

Khung tập hợp có nhiều lớp và giao diện. Tuy nhiên, trong phần này, chúng tôi sẽ giới hạn cuộc thảo luận của chúng tôi ở các giao diện Danh sáchBản đồ .

3.1. Trả lại giá trị của loại tương tự trong danh sách

Để bắt đầu, hãy viết lại ví dụ mảng trước bằng cách sử dụng Danh sách :

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

Giống như Number [] , tập hợp Danh sách chứa một chuỗi các phần tử kiểu hỗn hợp, tất cả đều có cùng kiểu chung.

3.2. Trả lại giá trị được đặt tên trong bản đồ

Nếu chúng tôi muốn đặt tên cho từng mục nhập trong bộ sưu tập của mình, một Bản đồ có thể được sử dụng để thay thế:

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

Người dùng phương thức getCoferencesMap có thể sử dụng các phím “ kinh độ” hoặc “ vĩ độ” với phương thức Map # get để truy xuất giá trị tương ứng.

4. Sử dụng các lớp vùng chứa

Không giống như mảng và tập hợp, các lớp vùng chứa (POJO) có thể bọc nhiều trường với các kiểu dữ liệu khác nhau .

Ví dụ: lớp Tọa độ sau có hai kiểu dữ liệu khác nhau, doubleString :

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 }

Sử dụng các lớp vùng chứa như Tọa độ cho phép chúng tôi lập mô hình các kiểu dữ liệu phức tạp với các tên có ý nghĩa .

Bước tiếp theo là khởi tạo và trả về một phiên bản của Tọa độ :

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

Chúng ta nên lưu ý rằng chúng ta nên tạo các lớp dữ liệu như Tọa độ là bất biến . Bằng cách đó, chúng tôi tạo ra các đối tượng đơn giản, an toàn theo chuỗi, có thể chia sẻ.

5. Sử dụng Tuples

Giống như vùng chứa, bộ giá trị lưu trữ các trường thuộc nhiều loại khác nhau. Tuy nhiên, chúng khác nhau ở chỗ không dành riêng cho ứng dụng .

Chúng chuyên biệt khi chúng ta sử dụng chúng để mô tả loại mà chúng ta muốn chúng xử lý, nhưng là vùng chứa mục đích chung của một số giá trị nhất định. Điều này có nghĩa là chúng ta không cần phải viết mã tùy chỉnh để có chúng và chúng ta có thể sử dụng thư viện hoặc tạo một triển khai đơn lẻ chung.

Một bộ tuple có thể là bất kỳ số lượng trường nào và thường được gọi là Tuple n, trong đó n là số trường. Ví dụ, Tuple2 là bộ hai trường, Tuple3 là bộ ba trường, v.v.

Để chứng minh tầm quan trọng của bộ giá trị, chúng ta hãy xem xét ví dụ sau. Giả sử rằng chúng ta muốn tìm khoảng cách giữa một điểm Tọa độ và tất cả các điểm khác bên trong một Danh sách . Sau đó, chúng ta cần trả về đối tượng Tọa độ xa nhất đó cùng với khoảng cách.

Trước tiên, hãy tạo một bộ hai trường chung:

public class Tuple2 { private K first; private V second; public Tuple2(K first, V second){ this.first = first; this.second = second; } // getters and setters }

Tiếp theo, hãy triển khai logic của chúng ta và sử dụng một phiên bản Tuple2 để bao bọc các kết quả:

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

Sử dụng Tuple2 trong ví dụ trước đã giúp chúng ta không phải tạo một lớp vùng chứa riêng biệt để sử dụng một lần với phương thức cụ thể này .

Giống như các thùng chứa, các bộ giá trị phải là bất biến . Ngoài ra, do bản chất mục đích chung của chúng , chúng tôi nên sử dụng các bộ giá trị nội bộ thay vì là một phần của API công khai của chúng tôi .

6. Thư viện bên thứ ba

Một số thư viện của bên thứ ba đã triển khai loại Cặp hoặc Bộ ba bất biến . Apache Commons Lang và javatuples là những ví dụ điển hình. Khi chúng tôi có các thư viện đó làm phụ thuộc trong ứng dụng của mình, chúng tôi có thể sử dụng trực tiếp các loại Cặp hoặc Bộ ba do thư viện cung cấp thay vì tự tạo chúng.

Hãy xem một ví dụ sử dụng Apache Commons Lang để trả về một đối tượng Cặp hoặc Bộ ba .

Trước khi bước tiếp, hãy thêm phụ thuộc commons-lang3 vào pom.xml của chúng tôi :

 org.apache.commons commons-lang3 3.9 

6.1. ImmutablePair từ Apache Commons Lang

The ImmutablePair type from Apache Commons Lang is exactly what we want: an immutable type whose usage is straightforward.

It contains two fields: left and right. Let's see how to make our getMostDistantPoint method return an object of the ImmutablePair type:

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. ImmutableTriple from Apache Commons Lang

The ImmutableTriple is pretty similar to the ImmutablePair. The only difference is, as its name tells, an ImmutableTriple contains three fields: left, middle, and right.

Now, let's add a new method to our coordinates calculation to show how to use the ImmutableTriple type.

We're going to go through all points in a List to find out the min, avg, and max distances to the given target point.

Let's see how can we return the three values with a single method using the ImmutableTriple class:

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. Conclusion

In this article, we've learned how to use arrays, collections, containers, and tuples to return multiple values from a method. We can use arrays and collections in simple cases since they wrap a single data type.

On the other hand, containers and tuples are useful in creating complex types, with containers offering better readability.

Chúng tôi cũng biết rằng một số thư viện của bên thứ ba đã triển khai các kiểu cặp và ba và xem một số ví dụ từ thư viện Apache Commons Lang.

Như thường lệ, mã nguồn của bài viết này có sẵn trên GitHub.