PERA Software Solutions GmbH

Returning multiple values from a method in Java

Returning multiple values from a method in Java

Problem

Sometimes it is necessary to return multiple values from a method. When you search the Internet for possible solutions, then you find a couple of suggestions:
  1. Return an
    Object[]
    or
    List<Object>
    .
  2. Modify an
    Object[]
    or
    List<Object>
    parameter.
  3. Return a
    Tuple<>
    with the values.
  4. Return a proper Object with the values as attributes.
  5. etc.
1. and 2. are very type unsafe because you have to know which type is at what position.
3. is at least typesafe but, if for example, you want to return multiple strings, then you have to know which tuple attribute contains what value.
4. is probably the cleanest solution but it means that you might end up with a lot of small "Result" classes.

Approach

Other curly brace languages like C++ or C# have built-in call-by-reference mechanism for this situation. C++ has reference parameter (
&
,
&&
) or pointer parameter (
&
,
*
). C# has the
out
and
ref
parameter modifiers.

Java on the other hand, has only call-by-value and so it is not possible to modify a given parameter directly. But if you call a method with an modifiable object, then you can modify the given object and store additional information. if we generalize this approach then we need a class which allows us to: Note that we don't need an initializing constructor because
out
parameters are only assigned in the called method and are not used to deliver a value to the called method.

So let's try with a very simple generic
Out<T>
: // Out.java public class Out<T> { private T _value = null; public void set(T value) { _value = value; } public T get() { return _value; } }

Examples

The following examples show how
Out<T>
can be used.

A simple example is splitting a string at a specified separator: // SplitString.java public class SplitString { public static void main(String[] arguments) { String keyValue = "language=java"; Out<String> key = new Out<>(); Out<String> value = new Out<>(); assertTrue(splitString(keyValue, '=', key, value)); assertEquals("language", key.get()); assertEquals("java", value.get()); } public static boolean splitString(String s, char separator, Out<String> before, Out<String> after) { int index = s.indexOf(separator); if (index >= 0) { before.set(s.substring(0, index)); after.set(s.substring(index + 1)); } return index >= 0; } } Another example simulates a technique which is used quite often in C++. You call a function which returns an error indicator and in case of an error fills an
error_code
. In the Java case we fill an exception output parameter: // OpenStream.java public class OpenStream { public static void main(String[] arguments) throws IOException { Out<IOException> streamException = new Out<>(); try (InputStream stream = tryOpenStream("somefile.txt", streamException)) { if (stream == null) System.out.printf("Couldn't open stream because %s%n", streamException.get().getMessage()); } } public static InputStream tryOpenStream(String fileName, Out<IOException> streamException) { try { return new FileInputStream(fileName); } catch (IOException exception) { streamException.set(exception); return null; } } } As a last example I'll show how the C#
TryParse
function could be implemented in Java: // Parse.java public class Parse { public static void main(String[] arguments) { String number = "12345"; Out<Integer> integer = new Out<>(); assertTrue(tryParse(number, integer)); assertEquals(12345, integer.get().intValue()); } public static boolean tryParse(String number, Out<Integer> integer) { try { integer.set(Integer.parseInt(number)); return true; } catch (NumberFormatException exception) { return false; } } }

Implementation

This is the
Out<T>
version which you can find in my JavaAidKit library. This version however is more strict and doesn't allow
null
values: package com.pera_software.aidkit.lang; import java.util.*; /** * A class which can be used to return a value from a method via a parameter. * * {@snippet : * public static boolean splitString(String s, char separator, Out<String> before, Out<String> after) * { * int index = s.indexOf(separator); * if (index >= 0) { * before.set(s.substring(0, index)); * after.set(s.substring(index + 1)); * } * return index >= 0; * } * * } * * @author P. Most * @see com.pera_software.aidkit.lang.InOut */ public class Out<T> { private T _value = null; /** * No initializing constructor because {@code out} parameters are only supposed to be set in the * called method. */ public Out() { } /** * Sets the value if not null, otherwise throws a {@code NullPointerException}. * @param value the non-null value to set * @throws NullPointerException if value is null */ public void set(T value) { if (value != null) _value = value; else throw new NullPointerException(); } /** * If a value is present, returns the value, otherwise throws {@code NoSuchElementException}. * @throws NoSuchElementException if there is no value present * @return the non-null value held */ public T get() { if (_value != null) return _value; else throw new NoSuchElementException(); } @Override public String toString() { return _value != null ? _value.toString() : ""; } public String toDebugString() { return String.format("Out<%s>: '%s'", _value != null ? _value.getClass().getSimpleName() : "null", _value != null ? _value : "null"); } }

Related

The JavaAidKit library also contains an
InOut<T>
type, which extends
Out<T>
and contains an additional constructor which allows to set an initial value. Because
InOut<T>
extends
Out<T>
you can use it whenever an
Out<T>
is expected.

Tips

Notes

After writing
Out<T>
and
InOut<T>
I've found this article Simulating C# ref parameter in Java.

Comments

Comments aren't available on this site, but there is a reddit thread.