TinusSky
TinusSky

Reputation: 1737

Best practice for returning multiple values in Java?

Today I've added a extra security check behind my login forms, to slow down brute force attacks. I've got multiple login forms and made a nice easy to call function that does all the checking and then returns the result.

public static ValidateLoginResult validateLogin(HttpServletRequest request, String email, String password) {

The problem is the result is not a single value, the result consists of:

boolean ok
String errorMessage
boolean displayCaptcha

For this I created a new class. This all works fine.

But I often have handy utility functions that return multiple values and start to find it a bit annoying to create a new class for the result every time.

Is there a better way of returning multiple values? Or am I just lazy? :)

Upvotes: 30

Views: 60749

Answers (7)

Bradley Willcott
Bradley Willcott

Reputation: 1

Here is a possible solution I picked up from another discussion, and enhanced a bit. It uses a public inner class with a private constructor:

public class Test {
    // Internal storage unit for the two values:
    // 'name' and 'age'.
    private Pair<String, Integer> info;

    public Test() {
        // Empty default constructor.
    }

    /**
     * The two values are stored in the Test class.
     *
     * @param name
     * @param age
     */
    public void setInfo(String name, int age) {
        info = new Pair<>(name, age);
    }

    /**
     * The 'name' and 'age' values are returned in a
     * single object.
     *
     * @return Both values in a Pair object.
     */
    public Pair<String, Integer> getInfo() {
        return info;
    }

    /**
     *  This is an Inner Class for providing pseudo 'tuplet'
     *  as a 'get' return value.
     *
     * @param <F> first internally stored value.
     * @param <S> second internally stored value.
     */
    public class Pair<F, S> {

        public final F first;
        public final S second;

        // This constructor is private to prevent
        // it being instantiated outside its
        // intended environment.
        private Pair(F first, S second) {
            this.first = first;
            this.second = second;
        }

        @Override
        public String toString(){
            return first + ", " + second;
        }
    }

    /**
     * main method for testing of the class only.
     *
     * @param args
     */
    public static void main(String args[]) {
        Test test = new Test();

        test.setInfo("Peter Smith", 35);
        Test.Pair<String, Integer> pair = test.getInfo();

        System.out.println("name: " + pair.first);
        System.out.println("age: " + pair.second);
        System.out.println(pair.toString());
    }
}

Upvotes: 0

NikkyD
NikkyD

Reputation: 2284

You can return an Object[] array, java autoboxes so its more easy to use. If it's just for a short distance handover, why not. Ofc its risky, possible class cast trouble, nullchecks etc

but its easy to write and use.

then again, a static inner class is quickly created and if you put it right next to the method returning it, you also know where to find it (usually near the origin)

Upvotes: 1

tucuxi
tucuxi

Reputation: 17955

You can define a Pair<A, B> class, and a Triplet<A, B, C> class, and that would solve the problem of returning 2 and 3 values while ensuring type-safety. In this particular case, the signature could be

public static boolean validateLogin(HttpServletRequest request,
            String email, String password, Pair<Message, Boolean> outputIfOk);

Or even better, in a servlet context, it may make sense to set some well-documented request attributes.

If you find yourself needing special classes to return results very often, you can most likely refactor those clases to share a common ancestor (say, have a RequestStatus which includes the 'ok' and 'message' fields).

Other than that, yes, you are being lazy -- custom clases will always be more self-documenting than Pairs and Triplets.

Upvotes: 5

Raibaz
Raibaz

Reputation: 9710

I can't really think of a better, cleaner and more object-oriented way of returning multiple values from a function than encapsulating them in a class.

Ideally, the multiple values you want to return are conceptually all part of the same class, so it makes sense to group them this way; if they don't, then you should probably decompose your function in some smaller functions that return each of the values you need outside of the function itself.

As far as I can tell, some IDEs also have facilities to help encapsulating multiple values in a class: for instance, Eclipse has Refactor --> Extract class...

Upvotes: 5

Bit-64
Bit-64

Reputation: 1

I'd probably just go the class route myself, but depending on what you want the function to return, you might be able to get away with returning some sort of container of values.

Upvotes: 0

Brian
Brian

Reputation: 6450

Not sure about "best practice" but a pragmatic option is to return a Map<String, String>? E.g.

myMap.put("result", "success");
myMap.put("usernameConfirmed", "bigTom");

return myMap;

Probably flies in the face of a million OO principles but I hear you re wanting to avoid a proliferation of result classes.

You could alternatively use Map<String, Object> and be stricter with type checks on stored objects: Strings, Booleans, Dates, etc.

Upvotes: 5

gma
gma

Reputation: 2563

No, this kind of structure doesn't exists nativily in Java, but you can look at JavaTuples library that may suit your need and provide a quite elegant solution. Using a Triplet<Boolean, String, Boolean>

Upvotes: 16

Related Questions