正在处理或禁止尝试资源可变未使用警告



在Java 17中,我有一个生成树结构的序列化程序。在生成子实体之前,我增加了缩进级别;之后我降低缩进级别。通常情况下,这应该在try/finally中完成,以防止串行器在出现错误时处于损坏状态:

increaseIndentLevel();
try {
serializeChildren()
} finally {
decreaseIndentLevel()
}

使用try with resources,我创建了一个聪明而优雅的小框架,确保以更流畅的方式完成这项工作:

protected Closeable increaseIndentLevel() {
indentLevel++;
return Close.by(this::decreaseIndentLevel);
}

Close.by()是我的助手类,它创建了一个Closeable,可以像上面一样降低缩进级别;我可以这样使用:

try (final Closeable indention = increaseIndentLevel()) {
serializeChildren()
}

不幸的是,打开linting的OpenJDKjavac17没有意识到我的聪明,而是抱怨道:

[警告]auto-closeable resource indention is never referenced in body of corresponding try statement

我知道尝试使用资源需要声明一些变量。例如,我不能说try (increaseIndentLevel())。(我也能猜到原因:这个功能的创建者没有足够的概括,而是为明显的99%的用例创建了不必要的限制性规则。事实上,在概念上没有必要在这里要求变量;如果主体需要引用某个东西,编译器足够聪明,可以注意到引用的变量不存在。(

知道如何避开这个警告吗?

作为最后的手段,我应该在@SuppressWarnings()中使用什么标识符来使这个警告在javac中消失?(我不得不压制这个警告,因为它把如此漂亮的解决方案变成了如此丑陋的东西。(

我会写这样的东西来避免可变性。如果没有看到更多的用例,很难知道该建议什么:

import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Indenter {
private final int indentLevel;
public Indenter(int indentLevel) {
this.indentLevel = indentLevel;
}
public void withIndent(Consumer<Indenter> f) {
f.accept(new Indenter(indentLevel + 1));
}
public void indent(String s) {
// must be a neater way to do this?
System.out.println(IntStream.range(0, indentLevel).mapToObj(i -> " ").collect(Collectors.joining()) + s);
}
public static void main(String[] args) {
Indenter i = new Indenter(0);
i.indent("x");
i.withIndent(i2 -> {
i2.indent("y");
});
}
}

根据@Mihe对这个问题的评论,一个解决方法是禁用编译器本身中的trylinting,就像Maven:中的这样

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<!-- suppress warnings for try-with-resources in
serializer indentation encpsulation -->
<arg>-Xlint:all,-try</arg>
</compilerArgs>
</configuration>
</plugin>

我仍然觉得这有点严厉。我考虑过使用@tgdavies的函数方法重构代码,但我还没有做出决定。我想我应该提供完整的解决方案。

我最终要做的是在Close实用程序中添加一个额外的(noop(helper方法。

try (final Closeable indention = increaseIndentLevel()) {
Close.suppressUnused(indentation);
serializeChildren()
}

另一种选择是添加到封闭收集器:

try (final CloseLine close = new CloseLine()) {
close.with(increaseIdentation());
serializeChildren()
}

我更喜欢第一个。两者都添加了两行,其中一行为空。第一个在实现和可读性方面都要简单得多,而且它得到了优化。

最新更新