【问题标题】:Return multiple times from a method?从一个方法多次返回?
【发布时间】:2013-03-20 08:51:21
【问题描述】:

我有一个需要一段时间才能完成的方法。我希望我的方法在返回“最终”结果之前返回“初步”结果。

我想了解是否可以这样:

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

     return firstResult;

     /*
     very long computation here
     */

     return finalResult;
}

这是否可能,或者您能建议某种解决方法吗?

【问题讨论】:

  • 你为什么不调用myMethod () 两次呢?就像一开始把一个变量设为假,这样它就不会执行第二个代码块,当你再次调用它时,让它是的。
  • 您期待某个方法的意外行为。
  • 请澄清您的问题并提供背景信息,例如这是否涉及 GUI?安卓?完全不同的东西?

标签: java multithreading concurrency return


【解决方案1】:

您可以将长时间运行的任务放在执行程序上(它将使用线程池异步执行任务)并返回一个Future,您可以稍后使用它来获得答案。当您在未来调用 get 时,它会阻塞直到任务完成,因此您可以立即使用初始答案并在稍后需要更精确时调用 Future.get,并给任务一些时间来完成。

返回值可能如下所示:

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();
    }
}

如果您预计长计算需要 5 秒,如果不到 5 秒,调用 getAnswer(5000) 将返回快速答案,否则将返回 longAnswer。

【讨论】:

    【解决方案2】:

    你不能简单地使用两种不同的方法吗?

    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;
        }
    
    }
    

    调用时:

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

    【讨论】:

    • 但是,longComput 可能不得不重做之前在shortComput 中执行的计算,或者依赖于结果在此期间没有改变的假设。
    • @WChargin 如果您将计算结果存储在计算机的字段中,则不会。并且如果Computer实例不能被多个线程同时使用,结果不会改变。
    • @WChargin 是的,这将是开发人员的有意选择;)
    【解决方案3】:

    是的。 SwingWorker 是要走的路。

    如果您不熟悉SwingWorker,它基本上是一个可以让您运行长时间计算的类。他们可以在完成后给出结果,或者在此过程中发布中期结果,这基本上就是你想要做的。

    来自"Tasks that Have Interim Results," Java 教程的一部分:

    在后台任务仍在工作时提供临时结果通常很有用。该任务可以通过调用 SwingWorker.publish 来完成。此方法接受可变数量的参数。每个参数必须是 SwingWorker 的第二个类型参数指定的类型。

    对于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));
        }
    }
    

    如果由于某种原因您不能使用SwingWorker,则需要使用异步线程来执行此操作。您可以尝试以下方法:

    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;
    }
    

    但这基本上是在重新发明轮子。

    【讨论】:

    • 我们怎么知道这个问题涉及到 Swing?
    【解决方案4】:

    不,这是不可能的,一个函数只能返回一次。一旦它返回,后续代码将不会被执行。但是,您可以更改代码设计,改为将输出写入参数引用的数据结构/放置为类成员。例如:

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

    【讨论】:

      【解决方案5】:

      我会使用侦听器模式。可以将自定义侦听器实例传递到方法中或添加到对象中。当长时间运行的方法执行时,您可以适当地调用侦听器,传递您需要的任何信息。这个监听器可以被多次调用。

      【讨论】:

        【解决方案6】:

        这在 Java 中绝对不可能。为什么不简单地将方法分成两个不同的方法?

        【讨论】:

        • 这在 Java 中绝对是可能的!
        【解决方案7】:

        只需使用一个条件:

        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;
        }
        
        }
        }
        

        编辑: 根据问题,我使用了一种方法:从一个方法中多次返回。

        【讨论】:

        • 没有。取而代之的是,您应该有两种方法。这基本上是错误的。
        • 您提供的代码设计得很糟糕。您使用静态标志将一些值传递给可以声明为参数的方法。未来更多你用它来分割逻辑。声明 method1 和 method2 并按顺序调用它们,您将实现同样的目标。这可以简化为单一的大型方法(这也很糟糕)。结论是你的例子没有解决问题,让代码的可读性降低。
        • @Vash 我想你没有仔细阅读这个问题。"一种方法" 这就是为什么使用单一方法;)
        【解决方案8】:

        这是可能的,但你必须引入线程。

        您的应用程序应该有两个线程mainworker

        main 线程是您的整个程序。在他的工作期间启动worker。 Worker 进行计算,在第一部分之后他可以设置一个 main 线程可以读取和显示的值。

        【讨论】:

        • 即使用SwingWorker;为什么要重新发明轮子?
        • 你还没有展示one方法如何返回two结果:/
        • @WChargin:我们怎么知道他的问题涉及到 Swing GUI?我可能错过了一些东西,但我没有在原始问题中看到提到这一点。正确的一般答案是按照 Nathan 的答案 (1+) 使用 Future。这就是 SwingWorker 所做的。
        • "这在 Java 中绝对是可能的!"这个评论(对一个告诉这是不可能并给出解决方法的答案)清楚地表明它是。
        • @joeyrohan,你完全正确。这就是为什么我没有写代码。它模糊地说OP需要和想要什么以及何时。他现在有了工具,他唯一需要的就是掌握它。 ;)
        猜你喜欢
        • 2017-10-02
        • 2013-04-30
        • 1970-01-01
        • 1970-01-01
        • 2013-02-12
        • 1970-01-01
        • 1970-01-01
        • 2020-07-30
        相关资源
        最近更新 更多