48

(別のクラスのmainメソッドから)IPアドレスを取得し、IPアドレスの範囲をループしてそれぞれにpingを実行するコードを作成しました。これにGUIフロントエンドがあり、クラッシュしていました(そのため、マルチスレッドを実行しました。問題は、pingコードの引数としてIPアドレスを呼び出し可能として使用できなくなったことです。すべてを検索しました。これのために、これを回避する方法を見つけることができないようです。呼び出し可能なメソッドが引数を取る方法はありますか?そうでない場合、私がやろうとしていることを達成する他の方法はありますか?

私のコードのサンプル:

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は、かつて取られた議論でした。

4

8 に答える 8

68

call()メソッドシグネチャでは許可されていないため、引数として渡すことはできません。

ただし、必要な情報をコンストラクター引数として渡すことができます。例えば

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

(私はいくつかのひどいコードスタイル違反を修正しました!!)

上記の「ボイラープレート」コーディングの一部を削除する方法があります(他の回答のいくつかを参照してください)。この場合、4行のコード(約40行のクラス)について話しているので、努力する価値があるとは確信していません。(しかしねえ、それはあなたのコードです。)

または、次のこともできます。

  • DoPingを内部クラス(またはラムダ)として宣言し、それfinal ipToPingが囲んでいるスコープ内のを参照するようにする、または

  • メソッドを追加しsetIpToPing(String ipToPing)ます。

(最後の方法では、DoPingオブジェクトを再利用できますが、欠点は、スレッドセーフにアクセスするために同期する必要があることです。)

于 2012-04-03T12:18:52.367 に答える
7

Jarleの答えに加えてCallable、匿名クラスのインスタンスとして作成する場合は、匿名クラスのfinal外部のフィールドを使用して、データをインスタンスに渡すことができます。

    final int arg = 64;
    executor.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            return arg * 2;
        }
    });
于 2012-04-03T12:19:19.083 に答える
6

メソッドシグネチャでは引数が許可されていないため、に引数を渡すことはできませcall()んが、これを回避する方法は少なくとも1つあります。

  1. ラップ/実装する抽象クラスを定義しCallable
  2. 結果を「注入」するセッターの実装call()

抽象クラスを定義します。

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());
于 2016-06-14T13:59:35.040 に答える
5

doPing-class(クラス名の大文字である必要があります)を作成するときは、コンストラクターでip-addressを送信します。call-methodでこのIPアドレスを使用します。

于 2012-04-03T12:14:07.773 に答える
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
     }
}
于 2012-04-03T12:17:54.003 に答える
1

ipAddressとそのアクセサメソッドなどのプロパティを定義する必要があります。constructorそして、その値をメソッドで、またはメソッドで渡しますsetterdoPingクラスでプロパティを使用します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
    }
}
于 2012-04-03T12:23:35.287 に答える
1

これに答えるのは非常に遅いことを私は知っています。それは8年以上前ですが、15日(!)前にアクティブであったことを考えると、これはJava8以降を使用している人にまだ役立つと思います。

PS、それはラムダを通して可能なビクターソロキンの答えの単なる構文糖衣です。

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);
于 2021-01-22T19:11:14.083 に答える
0

その値を「引数」として使用するために(効果的に)final変数を参照することが常に可能であるとは限りませんが、自分で快適な一般的な解決策を作成することができます。まず、この機能インターフェイスを定義します。

@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を作成する静的メソッドを提供します。このメソッドは、提供された引数(タイプT)を使用して呼び出すだけです。次に、次のように実装するクラスが必要です。Callablecall(T)DoPingCallableFunction

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を受け入れるように署名を変更しました。また、以前とは異なり、実装しています。その他の変更は軽微ですが、try-with-resource onを使用してリソースリークを防止し、入力収集ループ(からへの変更)に追加されて、可能な限り迅速に終了することを言及する価値があります。StringCallableFunctionCallableBufferedReaderbreakwhilefor

これで、次のようなコードを使用できます。

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

CallableFunction必要に応じて、他の場合に再利用することもできます。

于 2020-08-20T22:03:38.383 に答える