Поток с выражением 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);