编译器如何在多线程上下文中看到异常?

时间:2018-04-06 08:32:57

标签: java

我有两个包含相同变量名的异常类(但实际上在其他方面有所不同)。

class FooException extends Exception
{
    public String member;
}

class BarException extends Exception
{
    public String member;
}

在捕获站点,我想使用多个分组

catch (FooException | BarException e) {
    System.out.println(e.member);
}

然而,这会发出编译错误

  

的System.out.println(e.member);符号:变量成员位置:   异常类型的变量e

解决方案显然是打破多重包并复制功能体。但为什么这种语言没有"知道"该成员是否可用于复制中的所有例外?对我来说,它似乎搜索一个公共基类,并将e的类型设置为。这是看这个的正确方法吗?

4 个答案:

答案 0 :(得分:3)

  

对我来说,似乎要搜索一个公共基类,并将e的类型设置为

这正是Java所做的。此处的常见类型为Exception,因此e的类型为Exception。并且课程member中没有字段Exception

您需要为包含成员字段的所有异常创建超类。或者为每个Exception类型创建一个catch块。

编辑:或者它将寻找@OldCurmudgeon

所示的通用界面

答案 1 :(得分:2)

例外就像任何其他对象一样。为了能够以通用方式处理它们,它们必须实现通用功能。

interface HasMember {
    String getMember();
}

class FooException extends Exception implements HasMember {
    public String member;

    @Override
    public String getMember() {
        return member;
    }
}

class BarException extends Exception implements HasMember {
    public String member;

    @Override
    public String getMember() {
        return member;
    }
}

void throwFoo () throws FooException {
    throw new FooException();
}

void throwBar () throws BarException {
    throw new BarException();
}

public void test(String[] args) throws Exception {
    try {
        throwFoo();
        throwBar();
    } catch (FooException|BarException e) {
        System.out.println(e.getMember());
    }
}

添加abstract后,您可以稍微整理一下。

interface HasMember {
    String getMember();
}

abstract class ExceptionWithMember extends Exception implements HasMember{
    String member;

    @Override
    public String getMember() {
        return member;
    }
}

class FooException extends ExceptionWithMember {
}

class BarException extends ExceptionWithMember {
}

void throwFoo () throws FooException {
    throw new FooException();
}

void throwBar () throws BarException {
    throw new BarException();
}

public void test(String[] args) throws Exception {
    try {
        throwFoo();
        throwBar();
    } catch (ExceptionWithMember e) {
        System.out.println(e.getMember());
    }
}

答案 2 :(得分:0)

OldCurmudgeon已经提出的解决方案,所以我将添加JLS解释。

JLS 14.20. The try statement,您可以发现这种声明称为“多捕捉条款

  

一个catch子句,其exception参数表示为类型联合,称为多捕获子句。

稍后,指定参数的声明类型是这些类型的"Least Upper Bounds or lub"

  

异常参数的声明类型,表示其类型为与备用D1 |的并集D2 | ...... | Dn是lub(D1,D2,...,Dn)(§15.12.2.7)。

在您的情况下,lub(FooException | BarException)Exception

因此,在catch的阻止声明中,e的类型为Exception,这就解释了为什么你找不到这两个类的member

使用前面提到的答案,lub将是通用界面。

答案 3 :(得分:0)

  

但是为什么语言并不知道"知道"该成员可供所有人使用   多线程中的例外情况?

您所谈论的更多是dynamic typing方法。 Java是statically typed

允许您访问其中任何一个成员似乎很方便,但它为潜在的错误打开了大门。你的变量巧合地被称为同一件事。你没有做任何事情告诉编译器这些类型是相关的 - 为什么它只是推断它?

这是一个人为的例子,但这个例子说明了为什么编译器可能不想仅仅因为字段被称为同一个东西而想要尝试推断关系:

class Tree
{
    public final String bark = "brown and rough";
}

class Dog
{
    public final String bark = "loud and scary";
}

如果您想告诉编译器类型是相关的,Java会为您提供所需的所有工具。您可以使用继承或通用接口。