Java中的RAII设计模式

Des*_*Ice 18 java raii try-with-resources

来自C++背景,我是RAII模式的忠实粉丝.我已经广泛使用它来处理内存管理和锁管理以及其他用例.

使用Java 1.7,我看到我可以使用try-with-resources模式来创建RAII模式.

我使用RAII创建了一个示例应用程序并且它可以工作,但是我看到java中的编译器警告.

样品申请

try(MyResource myVar = new MyResource(..))
{
    //I am not using myVar here 
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误

warning: [try] auto-closeable resource node is never referenced in body of corresponding try statement
Run Code Online (Sandbox Code Playgroud)

我理解警告,这意味着我应该在try块中使用变量,我不需要一直这样做.

看看这个我假设Java并没有真正支持RAII,我可能误用了仅用于资源管理的功能,而不是C++中的RAII等价物.

几个问题:

  1. 我的理解是否正确?
  2. 忽视这些警告有多大风险?
  3. 如何通过蚂蚁忽略这些警告?
  4. 我有一个简单的方法来克服这个问题吗?

for 4我正在考虑将构造函数调用拆分为更简单的构造函数和像这样的实例方法

try(MyResource myVar = new Resource())
{
   myvar.Initialize()
   ....

}
Run Code Online (Sandbox Code Playgroud)

这解决了编译器的问题,但从设计的RAII中获取了本质.

Rad*_*def 14

1.我的理解是否正确?

或多或少.是的,您可以通过这种方式使用try-with-resources,是的,它在语义上与RAII相当.区别在于没有破坏释放,只有方法调用.

找到仅仅为了包装一些资源管理逻辑而编写的对象是不常见的,例如:

import java.util.concurrent.locks.Lock;

public class Guard implements AutoCloseable {
    private final Lock lock;

    public Guard(Lock lock) {
        this.lock = lock;
        lock.lock();
    }

    @Override
    public void close() {
        lock.unlock();
    }
}
Run Code Online (Sandbox Code Playgroud)
try(Guard g = new Guard(myLock)) {
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

如果您正在与其他程序员合作,您可能需要向少数人解释这意味着什么,但如果它漂浮在您的船上,我个人不会发现它有问题.

我不建议写的是奇怪的代码

try(AutoCloseable a = () -> lock.unlock()) {
    lock.lock();
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

这肯定会在代码审查中生成WTF.

2.忽略这些警告有多大风险?

没有风险.警告实际上只是一个通知.你知道,如果你知道它.

要摆脱警告你可以尝试:

try(@SuppressWarnings("unused")
    MyResource myVar = new MyResource())
Run Code Online (Sandbox Code Playgroud)

或者也许还可以看到'你怎么得到*ant*不打印出javac警告?' .

IDE应该为您提供全局或仅针对单个语句(不带注释)抑制特定警告的选项.

  • 你需要`@SuppressWarnings("try")`,它必须在方法级别.见[Victor Nazarov的回答](http://stackoverflow.com/a/41378498/152061),这对我有用. (3认同)
  • 为了补充这个答案,在 ANT 中忽略警告的方法是这样的 '<compilerarg value="-Xlint:all,-try"/>' (2认同)

Vic*_*rov 11

扩展Radiodef的答案.我认为RAI​​I使用try-with-resources是完全可以接受的java模式.但要实际压制警告

  • 你需要用@SuppressWarnings("try")而不是@SuppressWarnings("unused").
  • 并在方法上添加注释而不是变量声明

应用以上几点的示例:

   @SuppressWarnings("try")
   void myMethod1() {
       try(MyResource myVar = new MyResource(..)) {
           //I am not using myVar here 
       }
   }
Run Code Online (Sandbox Code Playgroud)

扩展模式本身.我已经广泛使用它来管理读写锁,它工作得很好.

在我的代码中,我曾经使用过这个技巧,有时先抢占一些资源以增加并发性,如下所示:

try (Guard g1 = new Guard(myLock1)) {
    someStuffThatRequiresOnlyLock1();
    try (Guard g2 = new Guard(myLock2)) {
        someStuffThatRequiresBothLocks();
        if (isSomething) {
            g1.close();
            someMoreSuffThatRequiresOnlyLock2()
        } else {
            someMoreSuffThatRequiresBothLocks();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

锁始终以相同的顺序获取,但是根据需要执行解锁,留下尽可能多的空间用于并发处理.使其与读写锁一起使用的调整是修改Guard类以允许重复关闭:

public class Guard implements AutoCloseable {
    private final Lock lock;
    private boolean isClosed = false;

    public Guard(Lock lock) {
        this.lock = lock;
        lock.lock();
    }

    @Override
    public void close() {
        if (!isClosed) {
           isClosed = true;
           lock.unlock();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)