Java 方法参数可选?

Java Optional for method argument?

我正在读这个 post 关于使用可选的方法参数和共识似乎是永远不要为此目的使用它们。

Guava Optional as method argument for optional parameters

但是在 API 方面(不是应用程序方面)是否完全没有此规则的例外情况?我想不出更简洁的方法来处理某些情况,尤其是在可能使用或不使用自变量参数的初始化情况下。

以我正在构建的这个枚举为例,它提供了我们业务使用的四个数据库连接。前三个不需要参数,因为 DbManager 工厂已经有了它需要的配置信息。但是对于正在使用的 SQLite 数据库,SQLite 连接需要 URL。因此,我需要将我的 Supplier 变成 Function<Optional<String>,DatabaseConnection>

这种使用 Optional 作为方法参数的情况是否合法?如果不是,我怎样才能使它可枚举?

private static enum DbConnectionSupplier {
    ORACLE(optArg -> DbManager.getOracleConnection()),
    MYSQL(optArg -> DbManager.getMySQLConnection()),
    TERADATA(optArg -> DbManager.getTeradataConnection()),
    SQLITE(optArg -> DbManager.getSQLiteConnection(optArg.get()));

    private final Function<Optional<String>, DatabaseConnection> supplier;
    private DbConnectionSupplier(Function<Optional<String>, DatabaseConnection> supplier) { 
        this.supplier = supplier;
    }

}

首先,如果您使用的是 lambda 表达式,那么您正在使用 Java 8 进行编译,您可以使用 java.util.Optional,而不是 Guava 的。

我想你有以下方法:

DatabaseConnection getConnection(String arg) {
   return supplier.apply(Optional.of(arg));
}

DatabaseConnection getConnection() {
   return supplier.apply(Optional.empty());
}

现在,它不能保护您免受呼叫 TERADATA.getConnection("BAR") 的人的伤害。另一方面,SQLITE.getConnection() 将在 optArg.get() 处以 NoSuchElementException(Java8) 或 IllegalStateException(Guava) 失败,因为可选的是空的。 从该异常中不清楚 getConnection 中预期的参数(好吧,它可能很清楚,但调用 Function.apply 时堆栈跟踪将是 "polluted")

以下实现避免使用 Optional,并清楚地表明是否需要参数。

TERADATA(()-> DbManager.getTeradataConnection()),
SQLITE(arg -> DbManager.getSQLiteConnection(arg)),
FOO(()-> DbManager.getFooConnection(),
    arg->DbManager.getFooConnection(arg));
//Foo supports both styles: with and without a parameter

private final Supplier<DatabaseConnection> supplier;
private final Function<String, DatabaseConnection> function;

private DbConnectionSupplier(Supplier<DatabaseConnection> supplier) { 
    this.supplier = supplier;
    this.function = null;
}    

private DbConnectionSupplier(Function<String, DatabaseConnection> function) { 
    this.function = function;
    this.supplier = null;
}    `

private DbConnectionSupplier(
    Supplier<DatabaseConnection> supplier,
    Function<String, DatabaseConnection> function) { 
    this.function = function;
    this.supplier = supplier;
}    

public DatabaseConnection getConnection(String arg) {
   if (function==null) throw ...
   return function.apply(arg);
}

public DatabaseConnection getConnection() {
   if (supplier==null) throw ...
   return supplier.get();
}