Lisa Anne
Lisa Anne

Reputation: 4595

Return multiple times from a method?

I have a method that takes a while to complete. I would like my method to return a "preliminary" result before returning the "final" result.

I would like to understand if it is possible to something like this:

public Object myMethod () {
    /*some computation here*/

     return firstResult;

     /*
     very long computation here
     */

     return finalResult;
}

Is this even possible or can you suggest some kind of workaround?

Upvotes: 7

Views: 10723

Answers (8)

joey rohan
joey rohan

Reputation: 3566

Simply use a condition:

public class TestMethod {


public static void main(String[] args)
{
boolean yes=false;
int something=compute(yes);
System.out.println(something);
yes=true;
something=compute(yes);
System.out.println(something);
}

public static int compute(boolean yes)
{
if(!yes)
{
    System.out.println("1st block");
return 22;
}
else
{
    System.out.println("2nd block");
return 33;
}

}
}

EDIT : I have used a single method as per the question : Return multiple times from a method.

Upvotes: 1

Nathan Hughes
Nathan Hughes

Reputation: 96434

You could put the long-running task on an executor (which would execute the task asynchronously using a thread pool) and return a Future that you can use later to get the answer. When you call get on the future, it blocks until the task finishes, so you can use your initial answer right away and call Future.get when you need more precision later, having given the task some time to finish.

The return value might look like this:

class MyMethodReturnStuff {

    private Object quickAnswer;
    private Future longAnswer;
    private long startTime = System.currentTimeMillis();

    MyMethodReturnStuff(Object quickAnswer, Future longAnswer) {
        this.quickAnswer = quickAnswer;
        this.longAnswer = longAnswer;
    }

    Object getAnswer(long expectedDelay) {
        return System.currentTimeMillis() - startTime < expectedDelay ?
        quickAnswer : longAnswer.get();
    }
}

If you expect the long calculation to take 5 seconds, calling getAnswer(5000) would return the quick answer if less than 5 seconds has passed and would return the longAnswer otherwise.

Upvotes: 6

gerrytan
gerrytan

Reputation: 41143

No it's not possible, a function can only return once. Once it returns subsequent code will not be executed. However you can change your code design to instead write the output into a data structure referenced by the argument / placed as a class member. For example:

public void longRunningFunc(List<String> output) {
  // some computation here
  output.add(..);

  // very long computation here
  output.add(..);
}

Upvotes: 2

Fabio
Fabio

Reputation: 652

This is definitely not possible in Java. Why don't you simply split your method in two different ones?

Upvotes: 1

wchargin
wchargin

Reputation: 16047

Yes. SwingWorker is the way to go.

If you're not familiar with SwingWorker, it's basically a class that lets you have long-running computations running. They can give a result when they're done or publish interim results along the way, which is basically what you're trying to do.

From "Tasks that Have Interim Results," a section of the Java Tutorial:

It is often useful for a background task to provide interim results while it is still working. The task can do this by invoking SwingWorker.publish. This method accepts a variable number of arguments. Each argument must be of the type specified by SwingWorker's second type parameter.

For example:

private class FlipTask extends SwingWorker<Void, FlipPair> {
    @Override
    protected Void doInBackground() {
        long heads = 0;
        long total = 0;
        Random random = new Random();
        while (!isCancelled()) {
            total++;
            if (random.nextBoolean()) {
                heads++;
            }
            // Here's your interim result, your "first return statement"
            publish(new FlipPair(heads, total));            
        }
        return null;
    }

    @Override
    protected void process(List<FlipPair> pairs) {
        FlipPair pair = pairs.get(pairs.size() - 1);
        headsText.setText(String.format("%d", pair.heads));
        totalText.setText(String.format("%d", pair.total));
        devText.setText(String.format("%.10g", 
                ((double) pair.heads)/((double) pair.total) - 0.5));
    }
}

If for some reason you can't use SwingWorker, you'd need to use asynchronous threads to do this. You could try something like:

interface Callback {
    public void computationComplete(Result r);
}
public Result doComputation(final Callback c) {
    // Do computation
    new Thread(new Runnable() {
        @Override
        public void run() {
            // Complete computation
            c.computationComplete(finalResult);
        }
    }).start();
    return firstResult;
}

but this is basically reinventing the wheel.

Upvotes: 2

sp00m
sp00m

Reputation: 48837

Couldn't you simply use two different methods?

public class Computer {

    private String commonVar1;
    private int commonVar2;

    public Object shortComput() {
        // short comput using commonVar1 and commonVar2
        return firstResult;
    }

    public Object longComput() {
        // long comput using commonVar1 and commonVar2
        return finalResult;
    }

}

When calling:

Computer c = new Computer();
Object firstResult = c.shortComput();
// do some short stuff with firstResult before launching:
Object finalResult = c.longComput();

Upvotes: 3

This is possible, but you will have to introduce to thread.

You application should have two threads main and worker.

The main thread, is your whole program. That during his work start the worker. Worker do the computation, after first part he can set a value that main thread can read and display.

Upvotes: -2

Chris Gerken
Chris Gerken

Reputation: 16390

I would use a listener pattern. A custom listener instance can be passed into the method or added to the object. As the long-running method executes, you can call the listener as appropriate passing whatever infomation you need. This listener can be called many times.

Upvotes: 1

Related Questions