Java异常安全可以减少丑陋吗?

时间:2012-06-10 23:42:23

标签: java raii exception-safety

给出以下代码:我们需要锁定模型,然后启动一个事务(可能会抛出异常,所以我们必须确保释放锁),然后做一些类似于获取数据库连接的东西(可能抛出异常),然后做一些可能抛出异常的东西,要求恢复事务。这是Java 6,因此我们没有Java 7的好东西。

SomeClass someMethod() 
throws SomeException {
  acquireWriteLock();
  try {
    startTransaction();
    try {
      DBConnection d = openDBConnection();
      try {
        doStuff(d);
        commitTransaction();
      } finally {
        d.close();
      }
    } catch (SomeException e) {
      handleSomeException(e);
      revertTransaction();
      throw e;
    } catch (Throwable t) {
      revertTransaction();  // Error: method must return a value of SomeClass
    }
  } finally {
    releaseWriteLock();
  }
}

这可以改写为更具可读性和更简洁吗?

只是为了好玩:当你看到以下内容时,你会怎么做?

DBConnection d = null;
try {
  acquireWriteLock();
  startTransaction();
  d = openDBConnection();
  try {
    doStuff(d);
    commitTransaction();
  } catch (SomeException e) {
    handleSomeException(e);
    revertTransaction();
  }
} finally {
  d.close();
  releaseWriteLock();
}

2 个答案:

答案 0 :(得分:2)

如果切换到Java 7,可以大大简化它。否则,你应该做的事情可能并不多。

可以尝试以下想法:

  • 将数据库连接+事务管理+锁管理重构为公共基类中的通用方法,每个事务类型都有一个子类

  • 将数据库连接+事务管理+锁管理重构为最终类中的常规方法,其中包含事务类型的接口和每个类的实现类。

然而,除非这种特殊模式被重复多次,否则这种重构可能是一个坏主意。 (你将创造一个本地成语,读者必须在意义变得明确之前学习成语。)

答案 1 :(得分:1)

如果不升级到Java 7,您可以将其中的一部分结合起来,这样您只需要一个try-catch。

SomeClass someMethod() throws SomeException {
   boolean committed = false;
   DBConnection d = null;
   acquireWriteLock();
   try {
      startTransaction();
      d = openDBConnection();
      doStuff(d);
      commitTransaction();
      committed = true;
   } catch (SomeException e) {
      handleSomeException(e);
      throw e;
   } finally {
     if( d != null ) d.close();
     if( !committed ) revertTransaction();
     releaseWriteLock();
   }
}

诀窍是确保revertTransaction()和DBConnection.close()不会抛出任何东西,但如果你不能这样做,那么你可以将releaseWriteLock()放在另一个finally子句中。如果你真的想要进一步改进,你可以做一些Stephen C提到的重构。执行诸如获取/释放writeLock,启动/回滚事务以及打开/关闭DBConnection之类的操作是在基类或一些抽象操作类中完成的。