web-dev-qa-db-ja.com

Lambda式のスレッド

42行目と43行目にエラーがあります:Thread t1=new Thread(()->prod.test());Thread t2=new Thread(()->cons.test());未処理の例外タイプInterruptedException。私がクイックフィックスしようとすると、catch Exceptionでtry catchが作成されますが、同じエラーが発生し、try catchで囲み続けるのと同じ方法で修正しようとします。

import Java.util.concurrent.locks.Lock;
import Java.util.concurrent.locks.ReentrantLock;

interface Predicate {
    public void test() throws InterruptedException;
}

class MyClass {
    int num = 0;
    Lock lock = new ReentrantLock();

    public void produce() throws InterruptedException {
        lock.lock();
        for (int i = 0; i < 1000; i++) {
            num++;
            Thread.sleep(1);
        }
        lock.unlock();
    }

    public void consume() throws InterruptedException {
        lock.lock();
        for (int i = 0; i < 1000; i++) {
            num--;
            Thread.sleep(1);
        }
        lock.unlock();
    }

    public int getNum() {
        return num;
    }

}

public class Main00 {

    public static void main(String[] args) throws InterruptedException {
        MyClass c = new MyClass();
        Predicate prod = c::produce;
        Predicate cons = c::consume;
        Thread t1 = new Thread(() -> prod.test());
        Thread t2 = new Thread(() -> cons.test());
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        long end = System.currentTimeMillis();
        System.out.println("time taken " + (end - start) + " num = "
                + c.getNum());
    }

}
14
T4l0n

チェックされた例外であるPredicateをスローするようにメソッドが宣言されている関数インターフェイスInterruptedExceptionを作成しました。ただし、ラムダ式の本体でtest()Thread を引数とする Runnableコンストラクターへのパラメーターとして呼び出し、その--- [run()メソッドをチェックされた例外をスローするように宣言されていません 。したがって、例外が本体でキャッチされないため、コンパイラエラーが発生します。

ちなみに、- 組み込みの関数型インターフェイス_Java.util.function.Predicate_ の関数メソッドがPredicateを返すため、独自のインターフェイスにbooleanという名前を付けると混乱する可能性があります。

run()Exceptionをスローできないため、例外をcatchにして処理する必要があります。例外とそのスタックトレースをログに記録する場合があります。例外をRuntimeExceptionでラップすることができます。どちらの方法でも、チェックされた例外をキャッチすると、コードをコンパイルできます。例:

_Thread t1 = new Thread(() -> {
    try {
        prod.test();
    } catch (InterruptedException e) {
        // handle: log or throw in a wrapped RuntimeException
        throw new RuntimeException("InterruptedException caught in lambda", e);
    }
});
_
16
rgettman

引数なしで単一のメソッドのみを実行する場合は、ラムダをメソッド参照で置き換えることができます。

例えば:

Thread t = new Thread(() -> {
        foo();
    });

より簡潔に表現することができます

Thread t = new Thread(this::foo);
4
MeetTitan

@rgettmanが言うように、Predicateという名前は不幸です...とにかく、Javaのdefaultメソッドを利用できます。

_interface PredicateButPleaseChangeMyName {

    void test() throws InterruptedException;

    default void tryTest() {
       try {
          this.test();
       } catch (InterruptedException e) {
          // handle e (log or wrap in a RuntimeException)
       }
    }
}
_

次に、メインメソッドで、デフォルトのtryTest()メソッドを呼び出してスレッドを作成します。

_Thread t1 = new Thread(() -> prod.tryTest());
Thread t2 = new Thread(() -> cons.tryTest());
_