オプションのパラメータをサポートする仕様はどれですか?
17 に答える
Javaでオプションのパラメータをシミュレートする方法はいくつかあります。
メソッドのオーバーロード。
void foo(String a、Integer b){// ...}
void foo(String a){foo(a、0); //ここで、0はbのデフォルト値です}
foo( "a"、2); foo( "a");
このアプローチの制限の1つは、同じタイプの2つのオプションのパラメーターがあり、それらのいずれかを省略できる場合は機能しないことです。
- Varargs。
a)すべてのオプションパラメータは同じタイプです:
void foo(String a, Integer... b) {
Integer b1 = b.length > 0 ? b[0] : 0;
Integer b2 = b.length > 1 ? b[1] : 0;
//...
}
foo("a");
foo("a", 1, 2);
b)オプションのパラメータのタイプは異なる場合があります。
void foo(String a, Object... b) {
Integer b1 = 0;
String b2 = "";
if (b.length > 0) {
if (!(b[0] instanceof Integer)) {
throw new IllegalArgumentException("...");
}
b1 = (Integer)b[0];
}
if (b.length > 1) {
if (!(b[1] instanceof String)) {
throw new IllegalArgumentException("...");
}
b2 = (String)b[1];
//...
}
//...
}
foo("a");
foo("a", 1);
foo("a", 1, "b2");
このアプローチの主な欠点は、オプションのパラメーターが異なるタイプである場合、静的タイプのチェックが失われることです。さらに、各パラメーターの意味が異なる場合は、それらを区別するための何らかの方法が必要です。
ヌル。以前のアプローチの制限に対処するために、null値を許可してから、メソッド本体の各パラメーターを分析できます。
void foo(String a、Integer b、Integer c){b = b!= null?b:0; c = c!= null?c:0; //...}
foo( "a"、null、2);
ここで、すべての引数値を指定する必要がありますが、デフォルトの値はnullの場合があります。
オプションのクラス。このアプローチはnullに似ていますが、デフォルト値を持つパラメーターにJava8オプションクラスを使用します。
void foo(String a、Optional bOpt){Integer b = bOpt.isPresent()?bOpt.get():0; //...}
foo( "a"、Optional.of(2)); foo( "a"、Optional.absent());
オプションで、メソッドコントラクトを呼び出し元に対して明示的にしますが、そのようなシグネチャは冗長すぎる場合があります。
更新:Java 8にはすぐに使用できるクラスが含まれて
java.util.Optional
いるため、Java 8ではこの特定の理由でguavaを使用する必要はありません。ただし、メソッド名は少し異なります。ビルダーパターン。ビルダーパターンはコンストラクターに使用され、別のBuilderクラスを導入することで実装されます。
class Foo { private final String a; private final Integer b; Foo(String a, Integer b) { this.a = a; this.b = b; } //... } class FooBuilder { private String a = ""; private Integer b = 0; FooBuilder setA(String a) { this.a = a; return this; } FooBuilder setB(Integer b) { this.b = b; return this; } Foo build() { return new Foo(a, b); } } Foo foo = new FooBuilder().setA("a").build();
マップ。パラメータの数が多すぎて、ほとんどのデフォルト値が通常使用される場合、メソッド引数をそれらの名前/値のマップとして渡すことができます。
void foo(Map <String、Object> parameters){String a = ""; 整数b=0; if(parameters.containsKey( "a")){if(!(parameters.get( "a")instanceof Integer)){throw new IllegalArgumentException( "..."); } a =(整数)parameters.get( "a"); } if(parameters.containsKey( "b")){// ...} // ...}
foo(ImmutableMap。<String、Object> of( "a"、 "a"、 "b"、2、 "d"、 "value"));
Java 9では、このアプローチはより簡単になりました。
@SuppressWarnings("unchecked") static <T> T getParm(Map<String, Object> map, String key, T defaultValue) { return (map.containsKey(key)) ? (T) map.get(key) : defaultValue; } void foo(Map<String, Object> parameters) { String a = getParm(parameters, "a", ""); int b = getParm(parameters, "b", 0); // d = ... } foo(Map.of("a","a", "b",2, "d","value"));
これらのアプローチのいずれかを組み合わせて、望ましい結果を達成できることに注意してください。
varargsはそれを(ある意味で)行うことができます。それ以外は、メソッドの宣言内のすべての変数を指定する必要があります。変数をオプションにしたい場合は、パラメーターを必要としないシグニチャーを使用してメソッドをオーバーロードできます。
private boolean defaultOptionalFlagValue = true;
public void doSomething(boolean optionalFlag) {
...
}
public void doSomething() {
doSomething(defaultOptionalFlagValue);
}
Java5.0にはオプションのパラメータがあります。次のように関数を宣言するだけです。
public void doSomething(boolean... optionalFlag) {
//default to "false"
//boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
doSomething();
あなたはとまたはdoSomething(true);
今電話することができます。
次のようなものを使用できます。
public void addError(String path, String key, Object... params) {
}
params
変数はオプションです。これは、オブジェクトのnull許容配列として扱われます。
不思議なことに、これについてはドキュメントで何も見つかりませんでしたが、機能します。
これは、Java 1.5以降では「新しい」ものです(Java 1.4以前ではサポートされていません)。
ユーザーbhootがこれについても以下で言及しているのがわかります。
Javaにはオプションのパラメータはありません。できることは、関数をオーバーロードしてからデフォルト値を渡すことです。
void SomeMethod(int age, String name) {
//
}
// Overload
void SomeMethod(int age) {
SomeMethod(age, "John Doe");
}
VarArgsとオーバーロードが言及されています。別のオプションはBlochBuilderパターンで、次のようになります。
MyObject my = new MyObjectBuilder().setParam1(value)
.setParam3(otherValue)
.setParam6(thirdValue)
.build();
ただし、そのパターンは、コンストラクターでオプションのパラメーターが必要な場合に最も適しています。
JDK> 1.5では、次のように使用できます。
public class NewClass1 {
public static void main(String[] args) {
try {
someMethod(18); // Age : 18
someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
} catch (Exception e) {
e.printStackTrace();
}
}
static void someMethod(int age, String... names) {
if (names.length > 0) {
if (names[0] != null) {
System.out.println("Age & Name : " + age + " & " + names[0]);
}
} else {
System.out.println("Age : " + age);
}
}
}
このようにメソッドのオーバーロードを使用して行うことができます。
public void load(String name){ }
public void load(String name,int age){}
また、@Nullableアノテーションを使用できます
public void load(@Nullable String name,int age){}
最初のパラメータとしてnullを渡すだけです。
同じ型変数を渡す場合は、これを使用できます
public void load(String name...){}
短縮版 :
3つのドットを使用する :
public void foo(Object... x) {
String first = x.length > 0 ? (String)x[0] : "Hello";
int duration = x.length > 1 ? Integer.parseInt((String) x[1]) : 888;
}
foo("Hii", );
foo("Hii", 146);
(@VitaliiFedorenkoの回答に基づく)
オーバーロードは問題ありませんが、デフォルト値を必要とする変数がたくさんある場合は、次のようになります。
public void methodA(A arg1) { }
public void methodA(B arg2) { }
public void methodA(C arg3) { }
public void methodA(A arg1, B arg2) { }
public void methodA(A arg1, C arg3) { }
public void methodA(B arg2, C arg3) { }
public void methodA(A arg1, B arg2, C arg3) { }
したがって、Javaが提供する可変引数を使用することをお勧めします。
APIエンドポイントの場合、エレガントな方法は「Spring」アノテーションを使用することです。
@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false, defaultValue = "hello") String id) {
return innerFunc(id);
}
この場合、innerFuncには変数が必要であり、APIエンドポイントではないため、このSpringアノテーションを使用してオプションにすることはできません。参照:https ://www.baeldung.com/spring-request-param
ビルダーのように機能するクラスを使用して、このようなオプションの値を含めることができます。
public class Options {
private String someString = "default value";
private int someInt= 0;
public Options setSomeString(String someString) {
this.someString = someString;
return this;
}
public Options setSomeInt(int someInt) {
this.someInt = someInt;
return this;
}
}
public static void foo(Consumer<Options> consumer) {
Options options = new Options();
consumer.accept(options);
System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}
のように使用
foo(o -> o.setSomeString("something").setSomeInt(5));
出力は
someString = something, someInt = 5
必要に応じて呼び出す必要のあるすべてのオプション値をスキップするには、または必要に応じて、オプションのパラメーターを使用しないfoo(o -> {});
2番目のメソッドを作成できます。foo()
このアプローチを使用すると、あいまいさを生じることなく、オプションの値を任意の順序で指定できます。varargsとは異なり、異なるクラスのパラメーターを持つこともできます。このアプローチは、アノテーションとコード生成を使用してOptionsクラスを作成できる場合はさらに優れています。
Javaは1.8でオプションをサポートするようになりました。私は、Androidでのプログラミングに固執しているため、オプションの型を使用するようにコードをリファクタリングできるまで、nullを使用しています。
Object canBeNull() {
if (blah) {
return new Object();
} else {
return null;
}
}
Object optionalObject = canBeNull();
if (optionalObject != null) {
// new object returned
} else {
// no new object returned
}
これは、実際のオプション型が導入される前でも古い質問ですが、最近ではいくつかのことを考慮することができます。-メソッドのオーバーロードを使用する-NULLを回避できるという利点があるオプション型を使用するオプション型は、通常使用される前にJava8で導入されました。 GoogleのGuavaなどのサードパーティのlibから。オプションをパラメーター/引数として使用することは、主な目的がそれを戻り時間として使用することであったため、過剰使用と見なすことができます。
参照:https ://itcodehub.blogspot.com/2019/06/using-optional-type-in-java.html
デフォルトの引数はJavaでは使用できません。C#、C ++、Pythonでは、それらを使用できます。
Javaでは、デフォルトのパラメーターを持つメソッド(関数)ではなく、2つのメソッド(関数)を使用する必要があります。
例:
Stash(int size);
Stash(int size, int initQuantity);
メソッドのオーバーロードまたはDataTypeの使用によってオプションのパラメータを作成できます。
| * | メソッドのオーバーロード:
RetDataType NameFnc(int NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(String NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(int NamePsgVar1, String NamePsgVar2)
{
// |* Code Todo *|
return RetVar;
}
最も簡単な方法は
| * | DataType...はオプションのパラメータにすることができます
RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
if(stringOpnPsgVar.length == 0) stringOpnPsgVar = DefaultValue;
// |* Code Todo *|
return RetVar;
}
複数のパラメーターを持つインターフェースを使用することを計画している場合は、次の構造パターンを使用して、applyを実装またはオーバーライドできます。これは要件に基づいた方法です。
public abstract class Invoker<T> {
public T apply() {
return apply(null);
}
public abstract T apply(Object... params);
}