Поток с выражением Lambda

У меня есть ошибка в строке 42 и 43: Thread t1=new Thread(()->prod.test());, Thread t2=new Thread(()->cons.test()); Необработанный тип исключения InterruptedException. Если я попытаюсь выполнить fastfix, он создаст try catch с catch Exception, он будет иметь ту же ошибку и попытается исправить его таким же образом, продолжая окружать его с помощью 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());
    }

}

Ответ 1

Вы создали функциональный интерфейс Predicate, чей метод объявлен для throw InterruptedException, который является проверенным исключением. Однако вы вызываете test() в теле лямбда-выражения как параметр конструктор Thread, который принимает Runnable, чей run() метод не объявляется, чтобы бросать любые проверенные исключения. Поэтому, поскольку исключение не попадает в тело, возникает ошибка компилятора.

Кстати, может возникнуть путаница назвать собственный интерфейс Predicate из-за встроенного функционального интерфейса java.util.function.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);
    }
});

Ответ 2

Как говорит @rgettman, имя Predicate несчастливо... В любом случае вы могли бы использовать методы default в Java:

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

Ответ 3

Если вы намереваетесь запустить только один метод без аргументов, вы можете заменить лямбду ссылкой на метод.

Например:

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

может быть более кратко выражено как

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