web-dev-qa-db-ja.com

Javaのラムダによる戻り値

今まで私は必要なすべての答えを見つけることができましたが、これは私を混乱させます。サンプルコードがあるとしましょう:

public class Animal {
   private String species;
   private boolean canHop;
   private boolean canSwim;
   public Animal(String speciesName, boolean hopper, boolean swimmer) {
     species = speciesName;
     canHop = hopper;
     canSwim = swimmer;
   }
  public boolean canHop() { return canHop; }
  public boolean canSwim() { return canSwim; }
  public String toString() { return species; }
}

public interface CheckAnimal {
   public boolean test(Animal a);
}

public class FindSameAnimals {
   private static void print(Animal animal, CheckAnimal trait) {
      if(trait.test(animal)){
         System.out.println(animal);
      }

   public static void main(String[] args) {
      print(new Animal("fish", false, true), a -> a.canHop());
   }
}

OCA Study Guide(Exam 1Z0-808)bookは、これらの2行は同等であると述べています。

a -> a.canHop()
(Animal a) -> { return a.canHop(); }

これは、舞台裏で、Javaがキーワードreturnをコードインに追加することを意味しますか?最初のケース?

答えがYESの場合、次のコードのコンパイル方法(他のすべてが適切な場所にあると想像してください):

static int counter = 0;
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(() -> counter++));

executeおよびRunnableのrunのシグネチャが次のとおりであることがわかっている場合:

void execute(Runnable command)
void run()

答えがNOの場合、どのようにJava何かを返す必要があるのか​​、いつ返さないのかを知っていますか?

a -> a.canHop()

無視したい場合booleanメソッドの戻り値の型。

9
Freeman

これは、舞台裏でJavaが最初のケースでコードにキーワードリターンを追加するということですか?

いいえ、コンパイラはバイトコードを生成します。同じバイトコードを生成する可能性がありますが、構文を変更せずに再度コンパイルします。

メソッドのブール戻り型を無視したかった。

考慮している機能インターフェイスに基づいて値を無視するオプションがあります。

_a -> a.canHop()
_

になり得る

_(Animal a) -> { return a.canHop(); }
_

または

_(Animal a) -> { a.canHop(); }
_

コンテキストに基づいていますが、可能であれば最初のものを優先します。

ExecutorService.submit(Callable<T>)およびExecutorService.submit(Runnable)を検討してください

_ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(() -> counter++); // has to be Runnable
es.submit(() -> counter++); // Callable<Integer> or Runnable?
_

戻り値の型を保存すると、_Callable<Integer>_であることがわかります

_final Future<Integer> submit = es.submit(() -> counter++);
_

試してみてください、ここに長い例があります。

_static int counter = 0;

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService es = Executors.newSingleThreadExecutor();

    // execute only takes Runnable
    es.execute(() -> counter++);

    // force the lambda to be Runnable
    final Future<?> submit = es.submit((Runnable) () -> counter++);
    System.out.println(submit.get());

    // returns a value so it's a Callable<Integer>
    final Future<Integer> submit2 = es.submit(() -> counter++);
    System.out.println(submit2.get());

    // returns nothing so it must be Runnable
    final Future<?> submit3 = es.submit(() -> System.out.println("counter: " + counter));
    System.out.println(submit3.get());

    es.shutdown();
}
_

プリント

_null
2
counter: 3
null
_

最初のsubmitRunnableを取るため、Future.get()nullを返します

2番目のsubmitはデフォルトでCallableであるため、Future.get()は_2_を返します。

3番目のsubmitvoid戻り値にしかなれないため、Runnableでなければならないので、Future.get()nullを返します。

11
Peter Lawrey

はい、単一のステートメントのみを指定する場合、その値はラムダから自動的に返されます。

次に、 Runnable は関数型インターフェースであるため、ラムダとして定義できます。戻り値の型はvoidであるため、ラムダ内の戻り値は無視されます。

3

returnステートメントのスコープについて混乱しています。 returnステートメント(コンパイラーによるバイトコードとして挿入されるか、プログラマーによるソースコードとして挿入される)は、ラムダを呼び出すメソッドからではなく、ラムダから返されます。

void foo() {
    Supplier<String> s = () -> { return "bar" };
    String s = s.get(); // s is assigned to "bar"
    // Execution continues as the return statement in the lambda only returns from the lambda and not the enclosing method
    System.out.println("This will print");
}
2
SamTebbs33