开发者

What's the best way to return a pair of values in Java? [duplicate]

This question already has answers here: How to return multiple values? [duplicate] (3 answers) Closed 3 years ago.

This is a small issue, as I could easily whip up a pair class to do the job. I don't really want to do this though, and I feel like there should be some simple, built-in, java-like way of r开发者_如何学Goeturning two values. What do you guys is the best, simplest way of doing this? Arrays? Some other data structure?


As far as I know, there is unfortunately no built-in representation of a pair in Java (and I certainly wish there was). Personally, when I code a project where I find that a pair class often would be useful, I create a generic Pair<T, U> class (which is probably what you were thinking of). Returning an array is a fast and simple way, but you might come to regret it later, because people who use your method will wonder whether the method might at some point return more than two values.

Whichever solution you choose: whenever you feel that you need a Pair, you should consider whether the time saved today by using e.g. a generic Pair class really is worth the loss of information to the next person who reads the code (and that person may well be you in six months). Writing a separate class for the return type takes more time now, but it would convey more information to those that use your method (namely, it tells the users what the return value represents, and contains useful member names for the two values). If it is a non-public method that is used only a few places, though, a Pair is more acceptable.


Using a container class is the easiest way.

 public class Pair<T, U> {         
    public final T t;
    public final U u;

    public Pair(T t, U u) {         
        this.t= t;
        this.u= u;
     }
 }


The closest thing I've seen to a "pair" in the standard libraries are the Map.Entry interface and the AbstractMap.SimpleEntry and AbstractMap.SimpleImmutableEntry classes that implement it.

If both objects are the same class an array is easier to use.


Apache Commons Lang3 provides an abstract Pair class with a couple implementations including ImmutablePair and MutablePair.


Three approaches, all not so great:

  1. Roll your own Pair<A, B>. You said you didn't want to do that.
  2. Return a Object[]. This is not type safe.
  3. Mimic out variables or pointers by supplying single element arrays as parameters.

An example of #3:

public boolean getUserDetails(String userId, String[] lastName, String[] firstName, Date[] dob) {
  assert lastName  != null && lastName.length  == 1;
  assert firstName != null && firstName.length == 1;
  assert dob       != null && dob.length       == 1;
  ...
}

The third option makes life painful for the caller.

So like I said, no nice solution.

As an aside, Scala uses various Tuple classes (up to 21-tuple, from what I remember) to help you with this.


There is a pair class in JavaFX, but you shouldn't use it. What you SHOULD use is something like this:

// We've skipped imports and package declarations
public final class YourClass {
  /* Assume there is a bunch of stuff here */

  // I don't know what method you're using, so forgive the silly example
  public YourClass.Pair sillyExampleOfPairs(String someString) {
    return new YourClass.Pair(someString, someString.length() * 13);
  }

  @Value // Lombok annotation.
  public static class Pair {
    String text;
    int integer;
  }

  // this is an even more succinct possibility
  @Value public static final class ShorterPair {String text; int integer}
}

While the name Pair here is obviously not that well chosen, and you should choose a more descriptive name, the obvious ways this will work (the fields are final private and you have a getter on each, because of the annotation), should not be lost on you. And while yes, this is slightly more wordy than using Pair, it's much more robust. What if you do need to add an extra parameter to the return value? You "only" need to change this class then. And you can update all the relevant JavaDocs immediately, which is also nice. If you have to change types, they would both entail similar amounts of work.

As long as you're only adding stuff, the old getText() and getInteger() methods would keep working as they did before. You also avoid having to add Yet Another Dependency to your projects. It's not a big win. Having Pair available is nice for prototyping, but it's not nice for later.

My final theoretical CS-y argument is that Pair is the same type as Pair. But if you have a Phonebook.Entry (with String and int) and say, Inventory.Item (with a name and a number of items we currently have inventoried), these two are very distinct types, which do very distinct things. You can't put one into the other. This is a Good Thing.

It's also much clearer for us poor bastards that have to go and debug your systems to see something like "com.name.project.something.something.Phonebook.Entry" in a stack trace than "org.apache.commons.lang3.tuple.Pair". One of these tells me WHAT I'm supposed to be looking at, and gives me some info on WHY I'm seeing a pair. The other says... nothing.

Now you might not care that you have to type for 3 extra seconds to save me 3 minutes. But I choose to believe in the goodness of your heart, and the nobility of your soul. Therefore, do the right thing.

Write a small static class instead.


I have been told by experts that when faced with the question of pairs, one of two things is true:

  1. You need to rethink your structure (this blunt answer doesn't help anyone)
  2. You need to build your own class to hold the pair

I would suggest that the second case is not all that abnormal. However, if what you are doing seems too trivial for introducing a new class, then using a Map could work, as others have suggested. If you are simply sending a single response back, then a Map seems like a bit much.

If a list of pairs sounds like it would work, and you need to maintain order, you could try a LinkedHashMap so that order is maintained.


if both are integers then I would advise a java.awt.Point but otherwise just create a container class with two objects x and y


Some observation of mine:

  1. Array is bulit-in, fast and easy to use, although imposible to expand its capacity. What if you want 3 values to be returned after 3 months?

  2. ArrayList/other colletions can be good, allows you to increment the capacity(initially 10). Note that Vector can be overkill in comparison to ArrayList when you only want to store 2 values to be fetched later. Map also can be good because it's always sorted and ordered.

  3. Some user-defined class: maybe an option if is meaningful(means that the data returned is important-ish to be a Java Bean), and you want to store more than just 2 integers into it. Readibility is better in case you add more notes in its Javadoc. Can be expanded as you like, just add fields in this class. Slower, but safer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜