【问题标题】:Why does wrapping an exception still request try-catch even when adding a throws?为什么即使添加 throws 包装异常仍会请求 try-catch?
【发布时间】:2015-07-24 19:20:53
【问题描述】:

我正在我自己的个人图书馆中使用SikuliX's API。这个想法是在外部项目中单独引用我的库,其中包含我需要的 SikuliX 部分。

现在,SikuliX 抛出了 FindFailed 异常,这是我需要的。我试着做:

public class FindFailed extends org.sikuli.script.FindFailed {
    FindFailed(String msg) { super(msg); }
}

这似乎是有道理的。但是,当尝试在其中一种方法中使用 throws 语句时:

import org.mylibrary.exceptions.FindFailed;

public static boolean clickFinishButton() throws FindFailed {
    pattern = PatternManager.loadPattern("my-image.png");

    screen.wait(pattern, 10);
    region = screen.exists(pattern);
    region.click(pattern);

    return true;
}

我仍然收到Unhandled exception type FindFailed 警告。将其改回原来的org.sikuli.script.FindFailed 当然可以,但是在外部项目中使用try-catch 将需要我重新添加相关的SikuliX jar 文件。

我想做的,只是简单地包装 SikuliX 抛出的 FindFailed 异常,并在我的库内部和外部使用它。

所有这一切的主要目标是用我自己的附加方法等封装另一个 API,这样当我引用这个库时,以后的项目也不必引用 SikuliX 的 jar。

- - - - My Library - - - <—————— External Project
|                      |
|        SikuliX       |
- - - - - - - - - - - - 

就目前而言,我需要执行以下操作:

- - - - My Library - - - <—————— External Project
|                      |                |
|        SikuliX       |                |
- - - - - - - - - - - -                 v
                                  SikuliX (Again)

到目前为止,我已经进行了如下更改,似乎可行。

public class FindFailed extends Exception {
    public FindFailed(Throwable cause) { super(cause); }
}

我现在不扩展任何第三方例外。相反,我继续执行以下操作:

public static boolean clickNewScan() throws FindFailed {
    pattern = PatternManager.loadPattern("my-image.png");   
    region = screen.exists(pattern);
    try {
        screen.wait(pattern, 60);
        region.click(pattern);
    } catch (org.sikuli.script.FindFailed e) {
        throw new FindFailed(e);
    }
    return true;
}

【问题讨论】:

  • 您提到 - “在外部项目中使用 try-catch 将需要我重新添加相关的 SikuliX jar 文件,这不是我想要的”- 因为您的自定义异常正在从库中扩展异常类,您将需要在类路径中使用该库。没有别的办法
  • 你设置完成的可能不是一个好主意毕竟,即使是FindFailed属于不同包的问题:Java theory and practice: The pseudo-typedef antipattern
  • 存在一些有效点。通过描述我的想法以及我这样做的原因,我或许可以更简短地澄清这个问题。

标签: java exception


【解决方案1】:

您可以通过将 SikuliX 中的所有调用封装到它们自己的接口中来做到这一点。我不知道SikuliX,所以我做一个玩具例子。

package third.party.library;

public class Foo {
    public void doSomething() throws ThirdPartyException {
        // Their code
    }
}

好的,所以你想包装这个功能而不依赖于他们的库。

package juxhin;

public interface FooBehavior {
    public void doSomething() throws MyException;
}

然后,当你需要他们的行为时,你可以使用你自己的实现:

package juxhin; // YOU write this class

public class ThirdPartyFooBehavior implements FooBehavior {
    private final Foo foo;

    public FooThirdPartyFooBehavior(Foo theirObject) {
        this.foo = theirObject;
    }

    @Override
    public void doSomething() throws MyException {
        try {
            foo.doSomething();
        } catch (ThirdPartyException e) {
            throw new MyException(e);
        }
    }
}

一旦您将它们的库封装在您自己的所有接口后面,那么您的类将只依赖于您自己的接口,这意味着您不必担心它们的异常。只要您使用非依赖实现重新实现这些接口,它们的库将完全可移除。

注意MyException 不应该扩展third.party.library.ThirdPartyException,因为这对你的问题没有帮助;它应该使用Exception(Throwable cause) 构造函数并将其从org.sikuli.script 类层次结构中删除。


不过,底线是您仍然必须以某种方式包含 SikuliX 中包含的代码。这就是存在Maven 之类的工具的原因,因此添加对jar 的引用非常容易。例如,如果您的 jar 依赖于 SikuliX,那么当您告诉新项目使用您的 jar 时,它将自动包含 SikuliX 引用,而无需您执行任何操作。你最终会得到这样的依赖树,它会自动为你完成所有这些工作:

我个人使用 Maven,但还有其他选项,例如 IvyGradle,它们可以做同样的事情 - 我不是在这里提倡使用任何特定工具,只是提倡使用 any 依赖工具。

【讨论】:

  • 我非常喜欢这个想法——当然我从来没有使用过 Maven(并且因为我从未使用过的事实而大喊大叫)但我可能不得不克服它。在这种情况下,我想让它尽可能简单。愚蠢的选择是在外部项目中也添加 SikuliX(这让我有点哭:-()
  • @Juxhin 我的答案的前半部分应该可以在没有需要任何依赖管理工具的情况下工作(尽管它们会让你的生活更轻松,我保证),只要你正在正确构建您的 jar,包括您的 jar 中的 SikuliX 代码。请参阅我的编辑,了解您可能比 Maven 更喜欢的另外两个选择。
  • @Juxhin 如果你有一个新问题,你应该问一个新问题。见Exit strategies for “chameleon questions”Edits should not invalidate existing answers。另外,请注意不要问yes/no question(例如,这种方法可以吗?)我相信你的方法很好。如果您尝试过,但效果不佳,请随时提出新问题。
  • @durron597 我明白了 - 我会留下它,因为它只是以防其他人遇到相同的查询并想知道我如何更改我的代码以满足我的需要。再次感谢你的帮助。非常感谢。
  • @Juxhin 以这种方式包装您的第三方库仍然有优势......可交换性。重新实现接口很容易,但检查所有代码并更改使用第三方对象的方式并不容易。
【解决方案2】:

从您不拥有的课程扩展绝不是一个好主意,应该避免。此外,它会使处理您的异常的人仍然拥有包含 org.sikuli.script.FindFailed 的 jar。

更好的方法是像这样包装异常:

public class MyFindFailedException extends Exception {
    MyFindFailedException(String message, Exception cause) {
        super(message, cause);
    }
}

然后像这样使用它:

public static boolean clickFinishButton() throws MyFindFailedException {
  try {
    pattern = PatternManager.loadPattern("my-image.png");

    screen.wait(pattern, 10);
    region = screen.exists(pattern);
    region.click(pattern);

    return true;
  } catch (FindFailed e) {
    throw new MyFindFailedException("something went wrong", e);
  }
}

【讨论】:

  • 那和其他有什么不同...你也“不拥有”Exception(请不要告诉我那是因为它带有 Java SDK)
  • 我认为您误解了这个问题。这里的主要问题是它是第三方异常类。并且 OP 想要扩展它,而不需要消费者明确地在他们的类路径上添加依赖库。
  • @ɐuıɥɔɐɯ Exception 有一个定义明确的已知实现。您可以轻松查看源代码。重写您不知道其实现的方法可能会破坏父类。诚然,在这个简单的例子中,这不是问题。 durron597 的回答很到位。
  • @Amit.rk3 我不是在回答这个问题,我指的是“从你不拥有的课程中扩展从来都不是一个好主意”;这同样适用于其他任何事情,JDK附带的东西并不意味着它是“神圣的”
  • @ɐuıɥɔɐɯ : 我的评论是为了这个答案,而不是你的评论:)
猜你喜欢
  • 2014-08-23
  • 1970-01-01
  • 1970-01-01
  • 2016-04-18
  • 2022-11-08
  • 2014-08-28
  • 2021-06-19
  • 2011-09-23
  • 2022-10-14
相关资源
最近更新 更多