How to write Java function that returns values of multiple data types?

76,709

Solution 1

No, you can't do that in Java.

You could return an Object though. And by returning an object you could technically return a derived class such as java.lang.Integer or java.lang.Boolean. However, I don't think it's the best idea.

Solution 2

You could technically do this:

public <T> T doWork()
{
   if(codition)
   {
      return (T) new Integer(1);
   }
   else
   {
      return (T) Boolean.FALSE;
   }
}

Then this code would compile:

int x = doWork(); // the condition evaluates to true
boolean test = doWork();

But you could most certainly encounter runtime exceptions if the method returns the wrong type. You also must return objects instead of primitives because T is erased to java.lang.Object, which means the returned type must extend Object (i.e. be an object). The above example makes use of autoboxing to achieve a primitive return type.

I certainly wouldn't recommend this approach because IMO you need to evaluate your use of exception handling. You catch exceptions in exceptional cases if you can do something with that exception (i.e. recover, persist, retry, etc.). Exceptions are an exception to the expected workflow, not a part of it.

Solution 3

no. the best you can do is return on instance of a class that handles all the things you might want to return.

something like

public class ReturnObj {
   public bool yesno; // yes or no
   public int val; // for int values
   public String mode; // mode describing what you returned, which the caller will need to understand.
}

obviously, you need to play with the names....

Also, this seems like a code smell. You might be able to remove the need to do something like this by qualifying what path you want outside of your function, and then call a specific function to get a boolean or a specific function to get an int, depending on the qualification.

Solution 4

IEEE Floating Point

Most languages will handle your specific example without Exceptions or union types because IEEE floating point includes a representation for NaN. In Java, use Double.NaN:

public static double quadratic(double a, double b, double c, int polarity) {
    double x = b*b - 4*a*c;

    // When x < 0, Math.sqrt(x) retruns NaN
    if (x < 0) {
        return Double.NaN;
    }
    return (-b + Math.sqrt(x) * polarity) / (2*a);
}

That produces your exact output that you wanted:

x = 4.0
x = 3.0
x = NaN
x = NaN

Exceptions

Exceptions are The Old Java Way of solving similar problems:

public static double quadratic(double a, double b, double c, int polarity) {
    double x = b*b - 4*a*c;
    // When x < 0, Math.sqrt(x) returns NaN
    if (x < 0) {
        throw new Exception("NaN")
    }
    return (-b + Math.sqrt(x) * polarity) / (2*a);
}

Here's your client code for an Exception.

a=1; b=-7; c=12;

// x = 4.0
try {
    System.out.println("x = " + quadratic(a, b, c, 1));
} catch (Exception iae) {
    System.out.println("Oopsie: " + iae.getMessage());
}

// x = 3.0
try {
    System.out.println("x = " + quadratic(a, b, c, -1));
} catch (Exception iae) {
    System.out.println("Oopsie: " + iae.getMessage());
}

// "invalid" coefficients.
a=4; b=4; c=16;

// Oopsie: NaN
try {
    System.out.println("x = " + quadratic(a, b, c, 1));
} catch (Exception iae) {
    System.out.println("Oopsie: " + iae.getMessage());
}

// Oopsie: NaN
try {
    System.out.println("x = " + quadratic(a, b, c, -1));
} catch (Exception iae) {
    System.out.println("Oopsie: " + iae.getMessage());
}

Union Types

To truly pass or return unrelated types to or from a method, you want Union types which Java does not really support. But Paguro provides Union Types which you can use in Java like this (using Or):

public static Or<Double,String> quadratic(double a, double b,
                                          double c, int polarity) {
    double x = b*b - 4*a*c;

    // When x < 0, Math.sqrt(x) retruns NaN
    if (x < 0) {
        return Or.bad("NaN");
    }
    return Or.good((-b + Math.sqrt(x) * polarity) / (2*a));
}

@Test public void testQuadradic() {
    double a, b, c;
    a=1; b=-7; c=12;

    // x = Good(4.0)
    System.out.println("x = " + quadratic(a, b, c, 1));

    // x = 3.0
    System.out.println(
            (String) quadratic(a, b, c, -1)
                    .match(good -> "x = " + good,
                           bad -> "Oopsie: " + bad));

    // "invalid" coefficients.
    a=4; b=4; c=16;

    // x = Bad("NaN")
    System.out.println("x = " + quadratic(a, b, c, 1));

    // Oopsie: NaN
    System.out.println(
            (String) quadratic(a, b, c, -1)
                    .match(good -> "x = " + good,
                           bad -> "Oopsie: " + bad));
}

Conclusion

For your specific example, just use Floating Point. For a more general solution, I find union types more useful than Exceptions. You can use union types as arguments to a method that might take two different inputs which have no common interface or ancestor. They are also more friendly to Functional Programming.

Solution 5

Write a function that returns an Object. Have it either return the Boolean or Integer wrapper objects. Then use instanceof to figure out which to use.

Share:
76,709
maček
Author by

maček

Updated on December 05, 2020

Comments

  • maček
    maček over 3 years

    For example, I want to create a function that can return any number (negative, zero, or positive).

    However, based on certain exceptions, I'd like the function to return Boolean FALSE

    Is there a way to write a function that can return an int or a Boolean?


    Ok, so this has received a lot of responses. I understand I'm simply approaching the problem incorrectly and I should throw some sort of Exception in the method. To get a better answer, I'm going to provide some example code. Please don't make fun :)

    public class Quad {
    
      public static void main (String[] args) {
    
        double a, b, c;
    
        a=1; b=-7; c=12;
        System.out.println("x = " + quadratic(a, b, c, 1));   // x = 4.0
        System.out.println("x = " + quadratic(a, b, c, -1));  // x = 3.0
    
    
        // "invalid" coefficients. Let's throw an exception here. How do we handle the exception?
        a=4; b=4; c=16;
        System.out.println("x = " + quadratic(a, b, c, 1));   // x = NaN
        System.out.println("x = " + quadratic(a, b, c, -1));  // x = NaN
    
      }
    
      public static double quadratic(double a, double b, double c, int polarity) {
    
        double x = b*b - 4*a*c;
    
        // When x < 0, Math.sqrt(x) retruns NaN
        if (x < 0) {
          /*
            throw exception!
            I understand this code can be adjusted to accommodate 
            imaginary numbers, but for the sake of this example,
            let's just have this function throw an exception and
            say the coefficients are invalid
          */
        }
    
        return (-b + Math.sqrt(x) * polarity) / (2*a);
    
      }
    
    }
    
  • Solomon Ucko
    Solomon Ucko over 7 years
    You should probably use an Enum, not a String
  • Solomon Ucko
    Solomon Ucko over 7 years
    I didn't downvote, but I do have a few questions/comments: 1. You should specify type parameters for the HashMap. 2. How do you make the keys?