有没有办法在可调用的方法中进行参数?

时间:2012-04-03 12:11:54

标签: java multithreading arguments ping callable

我已经创建了一段代码,它接受一个I​​P地址(来自另一个类中的main方法),然后循环遍历一系列IP地址,并在每个IP地址中执行。我有一个GUI前端,它正在崩溃(因此我为什么要完成多线程。我的问题是我不能再将IP地址作为我的ping代码中的参数作为其可调用的。我已经搜索了遍布对于这个并且似乎无法找到解决这个问题的方法。有一种方法可以让一个可调用的方法来获取参数吗?如果没有,是否还有其他方法可以完成我想要做的事情?

我的代码示例:

public class doPing implements Callable<String>{

public String call() throws Exception{

    String pingOutput = null;

    //gets IP address and places into new IP object
    InetAddress IPAddress = InetAddress.getByName(IPtoPing);
    //finds if IP is reachable or not. a timeout timer of 3000 milliseconds is set.
    //Results can vary depending on permissions so cmd method of doing this has also been added as backup
    boolean reachable = IPAddress.isReachable(1400);

    if (reachable){
          pingOutput = IPtoPing + " is reachable.\n";
    }else{
        //runs ping command once on the IP address in CMD
        Process ping = Runtime.getRuntime().exec("ping " + IPtoPing + " -n 1 -w 300");
        //reads input from command line
        BufferedReader in = new BufferedReader(new InputStreamReader(ping.getInputStream()));
        String line;
        int lineCount = 0;
        while ((line = in.readLine()) != null) {
            //increase line count to find part of command prompt output that we want
            lineCount++;
            //when line count is 3 print result
            if (lineCount == 3){
                pingOutput = "Ping to " + IPtoPing + ": " + line + "\n";
            }
        }
    }
    return pingOutput;
}
}

IPtoPing曾经是被采用的论据。

8 个答案:

答案 0 :(得分:46)

您不能将其作为参数传递给call(),因为方法签名不允许它。

但是,您可以将其作为构造函数参数传递; e.g。

public class DoPing implements Callable<String>{
    private final String ipToPing;

    public DoPing(String ipToPing) {
        this.ipToPing = ipToPing;
    }

    public String call() throws SomeException {
        InetAddress ipAddress = InetAddress.getByName(ipToPing);
        ....
    }
}

(我已经纠正了一些令人震惊的代码风格违规!!)

或者,您可以:

  • 将DoPing声明为内部类,并将其引用到封闭范围中的final ipToPing,或

  • 添加setIpToPing(String ipToPing)方法。

(最后一个允许重用DoPing对象,但缺点是你需要同步才能安全地线程访问它。)

答案 1 :(得分:7)

添加到Jarle的答案 - 如果您创建Callable作为匿名类的实例,您可以使用匿名类之外的final字段将数据传递到实例中:

    final int arg = 64;
    executor.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            return arg * 2;
        }
    });

答案 2 :(得分:5)

当您创建doPing类(应该是类名中的大写字母)时,请在构造函数中发送ip-address。在call-method中使用此ip-address。

答案 3 :(得分:5)

您无法将参数传递给call(),因为方法签名不允许它,但这里至少有一种解决方法

  1. 定义包装/实现Callable
  2. 的抽象类
  3. 实施一个setter,将结果“注入”call()
  4. 定义一个抽象类:

    import java.util.concurrent.Callable;
    
    public abstract class Callback<T> implements Callable<Void> {
        T result;
    
        void setResult (T result) {
            this.result = result;
        }
    
        public abstract Void call ();
    }
    

    定义应该触发回调的方法:

    public void iWillFireTheCallback (Callback callback) {
        // You could also specify the signature like so:
        // Callback<Type of result> callback
    
        // make some information ("the result")
        // available to the callback function:
        callback.setResult("Some result");
    
        // fire the callback:
        callback.call();
    }
    

    在您要拨打iWillFireTheCallback的地方:

    定义回调函数(甚至可以在方法内部):

    class MyCallback extends Callback {
        @Override
        public Void call () {
            // this is the actual callback function
    
            // the result variable is available right away:
            Log.d("Callback", "The result is: " + result);
    
            return null;
        }
    }
    

    然后在传递回调时调用iWillFireTheCallback

    iWillFireTheCallback(new MyCallback());
    

答案 4 :(得分:3)

final类中放置一些(doPing)字段,以及初始化它们的构造函数,然后将要在call()中使用的值传递给doPing的构造函数}}:

public class doPing implements Callable<String>  {
     private final String ipToPing;

     public doPing(String ip) {
         this.ipToPing = ip;
     }

     public String call() {
         // use ipToPing
     }
}

答案 5 :(得分:1)

您必须定义ipAddress等属性及其访问器方法。并在constructorsetter方法中传递其值。在doPing类中使用ipAddress属性。

class DoPing/* In java all classes start with capital letter */implements Callable<String>
{
    private String  ipAddress;

    public String getIpAddress()
    {
        return ipAddress;
    }

    public void setIpAddress(String ipAddress)
    {
        this.ipAddress = ipAddress;
    }

    /*
     * Counstructor 
     */
    public DoPing(String ipAddress )
    {
        this.ipAddress = ipAddress;
    }

    @Override
    public String call() throws Exception
    {
        // your logic
    }
}

答案 6 :(得分:0)

并非总是可以引用(有效地)最终变量以将其值用作“参数”,但是您可以自己制定舒适的通用解决方案。首先定义此功能接口:

@FunctionalInteface
interface CallableFunction<T, R> {

    public abstract R call(T arg) throws Exception;

    public static <T, R> Callable<R> callable(CallableFunction<T, R> cf, T arg) {
        return () -> cf.call(arg);
    }
}

此功能接口提供静态方法callable,该方法创建一个Callable实例,该实例仅使用提供的参数(类型T)调用call(T)。然后,您需要DoPing类来实现CallableFunction,如下所示:

public class DoPing implements CallableFunction<String, String> {

    @Override
    public String call(final String ipToPing) throws Exception {
        final var ipAddress = InetAddress.getByName(ipToPing);
        final var reachable = ipAddress.isReachable(1400);
        String pingOutput = null;
        if (reachable) {
            pingOutput = ipToPing + " is reachable.\n";
        }
        else {
            final var ping = Runtime.getRuntime().exec("ping " + ipToPing + " -n 1 -w 300");
            try (var in = new BufferedReader(new InputStreamReader(ping.getInputStream()))) {
                String line;
                for (int lineCount = 1; (line = in.readLine()) != null; ++lineCount) {
                    if (lineCount == 3) {
                        pingOutput = "Ping to " + ipToPing + ": " + line + "\n";
                        break;
                    }
                }
            }
        }
        return pingOutput;
    }

在这里,我们更改了call签名以接受String参数,现在它也实现了CallableFunction而不是以前的Callable。其他更改较小,但值得一提的是,我们在BufferedReader上使用try-with-resource防止了资源泄漏,并且break已添加到输入收集循环中(从{{1}起更改) }至while)以尽快终止。

现在您可以使用代码,例如像这样:

for

在其他情况下,您也可以在需要时重用 final var ping = CallableFunction.callable(new DoPing(), "127.0.0.1"); final var task = new FutureTask<>(ping); new Thread(task).start(); System.out.println(task.get(20, TimeUnit.SECONDS));

答案 7 :(得分:0)

我知道现在回答这个问题太晚了,考虑到它已经有 8 年的历史了,但在 15 天(!)前还很活跃,我觉得这仍然会对使用 Java 8 及更高版本的人有所帮助。

PS,这只是 Victor Sorokin 可能通过 lambdas 回答的语法糖。

public static Callable<String> generateCallableWithArg(final String input) {
    return () -> {
      Thread.sleep(5000); // someExpensiveOperationHere
      return "Return Value of " + input; //input can be used here
    };
  }

此外,我们可以编写一个静态辅助方法,可以将函数转换为 Callable。

public class CallableGenerator {

  public static <T,V> Callable<V> getCallableFromFunction(Function<T, V> function, T input) {
    return () -> function.apply(input);
  }
}

这可以用作

Callable<Integer> iAmCallable = CallableGenerator.getCallableFromFunction(i1 -> i1 * 2, 3);