绕过'无法引用定义的内部类中的非final变量'

时间:2013-04-07 15:28:06

标签: java closures processbuilder

我有以下代码,但是当我在新的Thread类之外声明String行时,我得到一个异常。我来自C#背景,所以我现在明白Java不支持真正的闭包。所以我的问题是:

如何在新线程之外声明一个字符串并在新线程中使用它?

  

不能引用定义的内部类中的非final变量行   用另一种方法

ProcessBuilder builder =
    new ProcessBuilder("/Users/Joe/Desktop/file", "-i", src);
builder.redirectErrorStream(true);
Process process = builder.start();
final InputStream is = process.getInputStream();
String line;
new Thread(new Runnable() {
    @Override public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            while ((br.readLine()) != null) {
                line += br.readLine() + "\n";
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }               
}).start();

4 个答案:

答案 0 :(得分:3)

line更改为StringBuilder并将其声明为final。然后更改run()方法以附加到StringBuilder

如果您在尝试阅读主线程中的join()之前line子线程,则无需使用StringBuffer

答案 1 :(得分:1)

你必须:

  1. 创建一个专门用于读取Process输出的新类(实现Future
  2. 在使用ExecutorService方法的结果之前等待其类的实例(作业)。
  3. 以下是代码示例:

    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class FutureJob {
    
       static class StreamToString implements Callable< String > {
    
          BufferedReader br;
    
          public StreamToString( InputStream in ) {
             br = new BufferedReader( new InputStreamReader( in ));
          }
    
          @Override public String call() throws Exception {
             StringBuilder buffer = new StringBuilder( 1024 );
             String line;
             while(( line = br.readLine()) != null ) {
                buffer.append( line );
                buffer.append( '\n' );
             }
             br.close();
             return buffer.toString();
          }
       }
    
       public static void main( String[] args ) throws Exception {
          ProcessBuilder   builder  = new ProcessBuilder( "cmd", "/C", "dir", "c:\\" );
          Process          process  = builder.start();
          ExecutorService  executor = Executors.newSingleThreadExecutor();
          StreamToString   toString = new StreamToString( process.getInputStream());
          Future< String > result   = executor.submit( toString );
          System.out.println( result.get());
          executor.shutdownNow();
       }
    }
    

    如果需要,调用者的阻塞等待由result.get()在内部进行。

答案 2 :(得分:0)

您应该创建另一个对象来保存和更改String。将此对象设为final并使用此对象方法更改字符串。

您可以尝试使用StringBuilder作为最终对象,并使用其append函数来修改字符串。

答案 3 :(得分:0)

或者,将line声明为内部类中的实例变量,因为您还没有在类之外使用它:

new Thread(new Runnable() {
    String line;
    @Override public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            while ((br.readLine()) != null) {
                line += br.readLine() + "\n";
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }               
}).start();