How to write Java function that returns values of multiple data types?
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);
}
}
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.
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.
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.
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.
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.
No, one return reference to a customer.
You can write a response object that encapsulates a boolean and an int together and set the values according to your whim.
But if I was a user I'd think your design was confusing.
my teacher had a cool idea for a tryParse C# like method in java hope it helps
import java.util.Scanner;
public class Program {
static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Enter number");
String input = scanner.next();
int[] num ={0};
if(tryParse(input,num))
System.out.println(num[0] * num[0]);
}
static boolean tryParse(String inputString,int[] outputInt){
try{
outputInt[0] = Integer.parseInt(inputString);
return true;
}catch(Exception e){
return false;
}
}
}
This may not be the best solution depending on what you want to do, but an easy way to solve the problem might be to have the function return an int or a constant outside the possible range (such as RETURNED_FALSE/TRUE) and check for that.
I would say it is possible. But not directly.
I haven't gone through the program given in the question. I am answering this knowing this is an old post. Might help someone.
Add your values to a Map like below. And get it with its key!
public static HashMap returnAnyType(){
String x = "This";
int a = 9;
HashMap<String, Object> myMap = new HashMap();
myMap.put("stringVal", x);
myMap.put("intVal", a);
return myMap;
}
String theStringFromTheMap = (String) returnAnyType().get("stringVal");
int theIntFromTheMap = (Integer) returnAnyType().get("intVal");
System.out.println("String : " + theStringFromTheMap + " is great !");
System.out.println("Integer: " + Math.addExact(theIntFromTheMap, 10));
Output (both are returned from same method):
String : This is great! Integer: 19
Note:
This is not a good practice. But it helps sometimes when it is needed!
Absolutely! In your case, since the return values can be positive, 0, negative, or false, probably the best return value would be a JSONObject. In your code, you would add this import:
import org.json.JSONObject;
and in the function:
JSONObject retval = new JSONObject();
double x = b*b - 4*a*c;
if(x < 0){
retval.put("result", false);
}
else{
retval.put("result", x);
}
You potentially could also add another key:value pair to the retval to include the result type to help with checking it in the calling function.
I wondered this same thing earlier this morning, and I made a nice little workaround that functioned well in my circumstance.
I wanted to build a table class that extended the AWT JPanel
, so that I could add it as a component to a JFrame
. It would need to take in an ArrayList<ArrayList<some value>>
that would store all of the tabledata (essentially a list of rows). The value, however, would sometimes be a String
, sometimes a double
, and sometimes an int
. So I created a class called Value
which has 3 constructors, a private enum Type
, and a return method called getContents()
. My class is arranged like so:
public class Value {
private String string;
private double decimal;
private int number;
private Type type;
public Value(int i) {
this.number = i;
type = Type.NUMBER;
}
public Value(double d) {
this.decimal = d;
type = Type.DECIMAL;
}
public Value(String s) {
this.string = s;
type = Type.STRING;
}
public Object getContents() {
switch(type) {
case STRING:return string;
case DECIMAL:return decimal;
default:return number;
}
}
private enum Type {
STRING, DECIMAL, NUMBER
}
To use this, I've used it in my GopherTable
(ignore the name please, it is relevant in the context of the software)
public class GopherTable extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private ArrayList<ArrayList<Value>> rows;
public GopherTable() {
rows = new ArrayList<ArrayList<Value>>();
}
public void addRow(ArrayList<Value> items) {
rows.add(items);
}
}
This solution worked perfectly in my case and AFAIK wouldn't offend very many people. Sometimes, the solution you are asking about is not the solution you are seeking. See this link for more on that.
inout parameters only work for objects that can be mutated. For String inout parameters, pass in StringBuilders instead of Strings, then replace() their values.
精彩评论