草庐IT

java - 针对异常的 Java 接口(interface)的正确设计

coder 2024-03-04 原文

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

5年前关闭。




Improve this question




我试图了解如何在 Java 中正确定义接口(interface),以及如何在语言(和运行时)中处理异常。

注意:也许这个问题已经被问到并得到了充分的回答,但我对 SO(和其他网站)的搜索没有发现任何直接解决设计问题和我提出的权衡的东西。如果可以找到一个类似的问题来回答我的问题,我会很高兴地删除这个问题。对于这个冗长的问题,我提前道歉,但我想尽可能清楚地说明问题。我也知道 controversy around checked exceptions ,但由于我无法更改语言并且仍然必须在其中工作,因此我想选择从长远来看会引起最少痛苦的方法。

我遇到的反复出现的问题是,当我尝试定义自己的接口(interface)时,我面临着如何指定接口(interface)成员允许哪些(如果有)异常的选择。问题是我无法知道哪些异常是有意义的,因为我不知道我的接口(interface)所有可能的实现可能是什么。举个例子,假设我们有以下接口(interface):

// purely hypothetical interface meant to illustrate the example...
public interface SegmentPartition {
    // option 1
    bool hasSegment(Segment s);
    // option 2
    void addSegment(Segment s) throws Exception;
    // option 3
    bool tryAddSegment(Segment s) throws TimeoutException, IOException, ParseException, XmlException, SQLException;
    // option 4
    void optimizeSegments() throws SegmentPartitionException;
}

此接口(interface)应预先声明哪些异常类型?我看到的选项是:
  • 不要声明任何异常,实现只能抛出 RuntimeException
  • 将每个方法声明为抛出 Exception
  • 尝试预测对这个接口(interface)有意义的每个可能的异常类型,并将它们声明为可抛出的异常。
  • 创建我自己的异常类型(例如 SegmentException )并要求根据需要将其与内部异常一起抛出以获取更多详细信息。

  • 这些方法中的每一种都有问题,并且并不完全清楚所有的权衡可能是什么,我已经为每种情况提到了一些。理想情况下,我不希望实现抛出任何异常,但这并不总是一个实际的限制。

    对于 选项 1 ,问题在于很多可能抛出的异常类型并不是从 RuntimeException 派生出来的(例如 IOException 或 TimeoutException)。当然,我可以将这些特定异常添加到接口(interface)中,然后也允许抛出其他 RuntimeExceptions,但是用户定义的异常呢?这似乎是一个糟糕的选择。

    选项 2 我们最终得到的接口(interface)似乎可能导致任何异常(我认为这是真的),并且没有为实现者提供关于实际抛出什么的指导。该界面不再是自我记录的。更糟糕的是,此接口(interface)的每个调用点都必须声明为抛出异常或将此接口(interface)的每个方法调用包装在 try{} catch(Exception) 中。 ,或创建一个捕获异常的块并尝试确定它是由接口(interface)实现还是该块中的其他东西抛出的。哎呀。或者,使用此接口(interface)的代码可以捕获实现可能抛出的特定异常,但它违反了开始使用接口(interface)的目的(因为它要求调用者知道实现的运行时类型)。在实践中,这是最接近我所知道的大多数其他语言在处理异常(C++、C#、Scala 等)方面所采用的选项。

    选项 3 我必须特别预测可以为我的接口(interface)定义的潜在实现,并声明最适合它们的异常。因此,如果我预计我的接口(interface)可能通过远程、不可靠的连接实现,我将添加 TimeoutException,如果我预计它可能使用外部存储实现,我将包括 IOException,等等。我几乎肯定可能会弄错......这意味着我将随着新的实现范式的出现而不断地搅动接口(interface)(当然,这会破坏所有现有的实现并要求他们将无意义的异常声明为被抛出)。这种方法的另一个问题是导致丑陋、重复的代码......特别是对于具有许多方法(是的,有时需要这些方法)的大型接口(interface),然后需要在每个实现点重复。

    选项 4 我必须创建我自己的异常类型,连同所有伴随它的包袱(可序列化、嵌套和内部异常、提出合理的层次结构等)。这里似乎不可避免地发生的是,您最终会为每种接口(interface)类型生成一个异常类型:InterfaceFoo + InterfaceFooException。除了这带来的代码膨胀之外,真正的问题是异常类型没有任何意义……它只是一种用于将特定接口(interface)的所有错误条件捆绑在一起的类型。在某些情况下,也许您可​​以创建异常类型的几个子类来指示特定的失败模式,但即使这样也是有问题的。

    那么,一般来说,在这里做什么才是正确的呢? 我意识到可能没有一成不变的规则,但我很好奇有经验的 Java 开发人员会选择做什么。

    谢谢。

    最佳答案

    throws Exception (它是一个受检异常)在一个接口(interface)中意味着你知道在什么条件下应该抛出这样一个受检异常。这意味着该接口(interface)已经对其实现有了一些了解。这不应该是这种情况。因此我会反对任何 throws Exception在一个界面中。如果接口(interface)抛出一个检查 Exception我建议简化它,将异常逻辑留给实现。

    关于java - 针对异常的 Java 接口(interface)的正确设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20305269/

    有关java - 针对异常的 Java 接口(interface)的正确设计的更多相关文章

    1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    2. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

      我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

    3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

      我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

    4. java - 等价于 Java 中的 Ruby Hash - 2

      我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

    5. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

      我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

    6. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

      在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

    7. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

      question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

    8. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

      我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

    9. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

      我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

    10. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

      我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

    随机推荐