11

I need a non-static instance method to return multiple values. For the sake of a simple example let's say these are boolean success and Object obj - but in the general case there could be more and they could be unrelated to each other. Can think of a few different ways of doing this:

Solution 1

private boolean aMethod(int aParam, Object obj) { ...set obj parameter & return value... }

Solution 2

private Pair<Boolean, Object> aMethod(int aParam) { ...set return pair values... }

Solution 3

private Object obj;
...
private boolean aMethod(int aParam) { ...set obj field & return value... }

Solution 4

private class MethodReturn { // Nested class - could be a separate class instead
    boolean success;
    Object obj;
    // ... Getters and setters omitted for brevity
}

private MethodReturn aMethod(int aParam) { ...set return object values... }

Are there any more possibilities I might have missed? And could anyone comment as to the pros and cons of each (and ideally, which might be the best to use under most circumstances)?

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • Good question. In most cases I personally use Solution 2. – CloudPotato Jul 20 '16 at 12:33
  • 3
    This should be moved in CodeReview – Mario Santini Jul 20 '16 at 12:34
  • Solutions 2 and 4 are the least surprising as at least they have no side effects and make it clearer what the method does. Solution four will be easier to refactor if you ever decide that you want to return something else. I would question the need for such a method in the first place as it seems to have more than one responsibility, and suggest refactoring to avoid this, – Mark Chorley Jul 20 '16 at 12:36
  • I'm use to ref out for dot net but there is in Java? http://stackoverflow.com/questions/2806545/does-java-have-something-like-cs-ref-and-out-keywords – mesutpiskin Jul 20 '16 at 12:38
  • The use case would be quite interesting. – Murat Karagöz Jul 20 '16 at 12:38
  • 3
    @MarioAlexandroSantini this would be off-topic on Code Review unless the OP posted their real actual working code, and not a method skeleton with code replaced by comments. See [A guide to Code Review for Stack Overflow users](http://meta.codereview.stackexchange.com/questions/5777/a-guide-to-code-review-for-stack-overflow-users) prior to referring posts to that site. – Phrancis Jul 20 '16 at 12:40
  • @MuratK Please see [this comment below](http://stackoverflow.com/questions/38481383/java-method-returning-multiple-values-best-practice?noredirect=1#comment-64365161) for the use case. – Steve Chambers Jul 20 '16 at 12:42
  • @Phrancis you're possibly right, I just point to the fact that here the OP is not asking for a issue, just some best practice/elegance of the solution. It's that wrong to point to post in the proper place, or you thing the OP contains something useful in stackoverflow? Thanks to clarify this. – Mario Santini Jul 20 '16 at 12:48
  • @MarioAlexandroSantini it sounds like it may be "too broad" for Stack Overflow. However, that does not necessarily make it on-topic for Code Review. Hypothetical/stub/pseudo code is always off-topic on Code Review, only real, working code is allowed. – Phrancis Jul 20 '16 at 12:51
  • `Tuple` (rather than `Pair`) would be a good name for a container class. It's pretty commonly used for arbitrary values. – Paul Samsotha Jul 20 '16 at 12:52
  • This may be the best solution Tuple @peeskillet – mesutpiskin Jul 20 '16 at 12:54
  • You may return Enum instead of Boolean and Pair. – Navrattan Yadav Jul 20 '16 at 13:27

6 Answers6

7

In general I'd go for the 4th or for a Map depending by the specific case, but if you need to return multiple unrelated values, I think that you have a serious design issue (Check https://en.wikipedia.org/wiki/Single_responsibility_principle)

In the specific case (after your comment), I'd definitely go with the 4th modeling the Response with all the required fields. Possibly you can also subtype with a ResponseSuccessful and ResponseFailure.

alros
  • 146
  • 6
  • Thanks for the answer. To elaborate slightly on the actual use case, a private save method in a Spring-MVC controller is returning an indication of whether the operation was successful and the page to redirect to. I could be wrong but don't think this is in violation of the SRP. – Steve Chambers Jul 20 '16 at 12:40
  • 1
    then they are not unrelated and you can model it in a Response object that models an HTTP Request (or part of it) – alros Jul 20 '16 at 12:44
  • @SteveChambers If the operation's not successful, throw an exception. – chrylis -cautiouslyoptimistic- Jul 20 '16 at 12:46
  • @chrylis Agree that may be a better design but it doesn't fit with code that is already written - there is already boilerplate code for displaying warnings and errors in a panel at the top of a redirected page. – Steve Chambers Jul 20 '16 at 12:52
  • 2
    @chrylis: Not always a good option, e.g. from a functional programming POV, throwing an exception is just like a `goto` jump. It's better to handle errors with the use of `Either`, `Optional` or callbacks. – charlie Jul 20 '16 at 13:18
  • 1
    @charlie A functional pipeline is an entirely different paradigm from standard Java code. Sure, a Promise-like callback chain makes more sense there, but that's a different environment. – chrylis -cautiouslyoptimistic- Jul 20 '16 at 13:25
  • 2
    I agree that Exceptions should be used only in exceptional cases and not for common reasons such as a validation failure. Obviously real world applications (and frameworks!) don't always agree on that! – alros Jul 20 '16 at 13:35
  • In my team's webapp, we return a custom `Status` object for most calls like this. If a `Status` object is ever instantiated with a `Status.FAILURE` argument, we log the `Status` object along with any Exceptions thrown and then the process that called the method knows something went wrong. – Zircon Jul 20 '16 at 14:15
5

Solution 5 — a callback

With a callback, you can even return multiple 2-tuples:

private void aMethod(int aParam, BiConsumer<Boolean, String> callback) {
    …
    callback.accept(success1, msg1);
    …
    callback.accept(success2, msg2);
    …
}

Usage:

aMethod(42, (success, msg) -> {
    if (!success) {
        log.error(msg);
    }
});

Also, you can return an (n>2)-tuple by composition, without a custom class — e.g. for a 4-tuple:

<A, B, C, D> void aMethod(int aParam, BiFunction<A, B, BiConsumer<C, D>> callback) {
    callback.apply(a, b).accept(c, d);
}

aMethod(42, (a, b) -> (c, d) -> log.debug("" + a + b + c + d));

To comment on your solutions:

  • Solution 1: it's a bad practice to modify arguments, moreover, String is immutable
  • Solution 2: commonly used pattern, a Pair<T,U> or a Tuple2<T,U>
  • Solution 3: fragile and discouraged, it has all drawbacks of state-fullness (concurrency, etc.)
  • Solution 4: similar to #2, e.g. class MethodReturn implements Pair<Boolean, String> {}

N.B.: The MethodReturn can be an interface you implement on the fly (at the return point), e.g.:

private MethodReturn aMethod(int aParam) {
    …
    return new MethodReturn() {
        @Override
        public Boolean first() { return success; }

        @Override
        public String second() { return msg; }
    };
}
charlie
  • 1,478
  • 10
  • 20
  • Re: Solution 2 comment - are you are referring to the custom `Tuple2` implementation in [this answer](http://stackoverflow.com/questions/457629/how-to-return-multiple-objects-from-a-java-method#457675)? – Steve Chambers Jul 21 '16 at 09:16
  • 1
    @SteveChambers: Yes, or any other, like [javatuples](http://www.javatuples.org). But, as explained in this [Tuples](https://dzone.com/articles/whats-wrong-java-8-part-v) article, **function arguments** also form a **tuple**, thus calling a **callback** is a direct equivalent of **returning a tuple**. Besides, the callback can be called multiple times by the receiving function. – charlie Jul 21 '16 at 17:03
  • 1
    This is needlessly complex for a simple method. It has utility in returning values from threaded programs and Futures, but it complicates understanding the flow control in a single threaded program. – scott m gardner Apr 26 '18 at 00:35
2

In my programs, if the returned objects are logically related by something, they may need to have their own class: a boolean and a String may be a MessageStatus (edit: i see this is your 4th solution).
To give you a concrete example:

public class TurnToken {
/**
 * Number of available Quick Actions
 */
private int quickActionTimes;
/**
 * Number of available Main Actions
 */
private int mainActionTimes;
[...Etcetera with setters and getters]

This class is only composed by two integers, but it logically represents something which may be considered an entity itself

EDIT: I accidentally cancelled the first part. If your objects are not primitive, but are logically correlated, you may create an interface to collect them:

public interface Adjectivable{
//If they have a commong method even better}

and your method

public List<Adjectivable> myMultiReturningMethod{
    List<Adjectivable> theStuffToReturn = new ArrayList<>();
    Etcetera...
}
Vale
  • 1,104
  • 1
  • 10
  • 29
2

Solution 1 won't work, as strings in java are immutable,

Solution 3 you can't always apply, as you holding result in instance, you might nor be able to run your method from that instance as long as you need result.

So that leaves us with solutions 2 and 4 which are very similar. As in both cases you return result wrapped in custom class. If you think Pair is enough for you, i would say, use it, and go with solution number 2.

user902383
  • 8,420
  • 8
  • 43
  • 63
  • Thanks for the answer and nice spot about solution 1! I didn't like the idea of Solution 3 either, not sure I completely understood your comment but does it apply as it is a private method? (However I think this solution might also have concurrency issues so had pretty much discounted it.) I guess the choice between 2 and 4 may well come down to personal preference, am currently leaning towards 4... – Steve Chambers Jul 20 '16 at 13:02
  • **Update:** Have now changed the question to use an Object instead of a String to address the Solution 1 issue. – Steve Chambers Jul 20 '16 at 13:28
1

You may use enum here if results are fixed.

public Enum Status {

     OK("OK"),
     CREATED("Created"),
     ACCEPTED("Accepted"),
     NO_CONTENT("No Content"),
     FORBIDDEN("Forbidden"),
     NOT_FOUND("Not Found");

     private final String reason;

     Status(final String reasonPhrase) {
        this.reason = reasonPhrase;
    }
}

 private Status aMethod(int aParam) {
  ................
  return Status.OK;
 }
Navrattan Yadav
  • 1,993
  • 1
  • 17
  • 22
  • Or even combine it with the solution #2: `enum Status implements Pair`, and then let the `private Pair aMethod()` decide when to return a predefined status like `return Status.OK;` or a new one like `return pairOf(success, msg);`, depending on the situation. – charlie Jul 20 '16 at 14:32
  • Think this answer is referring to the example / use case here rather than the general case where parameters may not be enums. – Steve Chambers Jul 21 '16 at 09:19
-2

Use

Object[] aMethod(){ 

//Create and fill an array of object and return it

}

You can fill as much and different values as you need to caller.

Hulk
  • 6,399
  • 1
  • 30
  • 52
Gürhan
  • 9
  • 3