使用Lambda表达式的线程

18

第42行和43行出现错误:Thread t1=new Thread(()->prod.test());Thread t2=new Thread(()->cons.test());未处理的异常类型 InterruptedException。如果我尝试快速修复它,它会创建带有异常捕获的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());
    }

}
3个回答

22
你创建了一个名为Predicate的函数式接口,该接口中的方法声明抛出一个受检异常InterruptedException。但是,你在lambda表达式的主体中作为参数调用了test(),将其传递给接受RunnableThread构造函数,而Runnable接口的run()方法不声明抛出任何受检异常。因此,在lambda表达式的主体中未捕获异常,导致编译器报错。

顺便提一下,给自己命名一个名为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);
    }
});

在相应的 try 块中,从未抛出异常 'java.lang.InterruptedException'。 - ShadowGames
1
@ShadowGames 这个特定的 Predicate 定义声明了 test 会抛出 InterruptedException,因此它可能被抛出并且必须被捕获。 - rgettman

10

如果你只打算运行一个不带参数的方法,你可以用一个方法引用替换Lambda表达式。

例如:

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

可以更简洁地表达为:
Thread t = new Thread(this::foo);

开始它

t.start();

我假设你仍然需要调用t.start()(这与问题无关,但在我理解lambda之前最好问一下!)。 - Sridhar Sarnobat

3

正如 @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());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接