2つの異なるvarargsを期待するメソッドをJavaで作成する方法はありますか? コンパイラは開始位置と終了位置を認識していないため、同じ種類のオブジェクトを使用することはできません。しかし、なぜ異なるオブジェクト型に対してもそれができないのでしょうか?
例えば:
public void doSomething(String... s, int... i){
//...
//...
}
このようなメソッドを作成する方法はありますか? ありがとうございました!
2つの異なるvarargsを期待するメソッドをJavaで作成する方法はありますか? コンパイラは開始位置と終了位置を認識していないため、同じ種類のオブジェクトを使用することはできません。しかし、なぜ異なるオブジェクト型に対してもそれができないのでしょうか?
例えば:
public void doSomething(String... s, int... i){
//...
//...
}
このようなメソッドを作成する方法はありますか? ありがとうございました!
可変引数は 1 つだけです。しかし、 asList() を使用すると、ほぼ同じように便利になります。
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
Java では、1 つのvarargs
引数のみが許可され、署名の最後のパラメーターである必要があります。
ただし、とにかくそれを配列に変換するだけなので、2 つのパラメーターを明示的な配列にする必要があります。
public void doSomething(String[] s, int[] i){
呼び出しコードが次のようになる可能性のある API 設計
doSomething("a", "b").with(1,2);
「流れるような」API を介して
public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
危険なのは、プログラマーが呼び出しを忘れた場合ですwith(...)
doSomething("a", "b"); // nothing is done
多分これは少し良いです
with("a", "b").and(1, 2).doSomething();
vararg
許可されるのは1 つだけです。これは、複数のvararg
引数があいまいであるためです。たとえば、同じクラスの 2 つの可変引数を渡した場合はどうなるでしょうか。
public void doSomething(String...args1, String...args2);
args1 はどこで終わり、args2 はどこで始まりますか? または、ここでもっと紛らわしいことはどうですか。
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass は SuperClass を拡張するため、args1 または args2 に合法的に存在できます。varargs
この混乱が、1 つしか許可されない理由です。
varargs
メソッド宣言の最後にもなければなりません。
代わりに特定の型を 2 つの配列として宣言するだけです。
この種のことは時として便利ですが、通常、Java の制限にぶつかっていることに気付いた場合は、おそらく何かを再設計して、はるかに優れた結果を得ることができます。他に考えられる方法はいくつかあります...
2 つのリストが関連している場合は、おそらく 2 つの異なるリストのラッパー クラスを作成し、ラッパーに渡します。コレクションのラッパーは、ほとんどの場合良いアイデアです。コレクションに関連するコードを追加する場所を提供します。
これがデータを初期化する方法である場合は、文字列から解析します。たとえば、"abc, 123:def, 456:jhi,789" は、2 つの分割ステートメントとループ (2 ~ 3 行のコード) で分割するのが非常に簡単です。そのような文字列を解析して、メソッドにフィードする構造体にする小さなカスタム パーサー クラスを作成することもできます。
うーん-正直なところ、データの初期化は別として、なぜとにかくこれをやりたいのかさえわかりません。他の場合は、2つのコレクションを渡し、varagにまったく興味がないでしょう。
これは古いスレッドですが、それでも役立つと思いました。
私が見つけた解決策はあまりきちんとしていませんが、うまくいきます。重労働を処理するために別のクラスを作成しました。必要な 2 つの変数とそのゲッターしかありません。コンストラクターは、set メソッドを独自に処理します。
方向オブジェクトとそれぞれの Data オブジェクトを渡す必要がありました。これにより、不均一なデータ ペアの問題も解決されますが、これはおそらく私の使用上のニーズにのみ対応しています。
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* @return the node
*/
public Node getNode() {
return node;
}
/**
* @return the direction
*/
public Directions getDir() {
return dir;
}
}
次に、このクラスをメソッドの可変引数として渡します
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
この「パターン」に関する別の質問を読んだところですが、すでに削除されているため、この解決策が見られなかったので、この問題に対する別のアプローチを提案したいと思います。
開発者に List または Array で入力パラメーターをラップするように強制する代わりに、"curry" アプローチ、またはより良いビルダー パターンを使用すると便利です。
次のコードを検討してください。
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
このように見てわかるように、必要なときに必要なタイプの新しい要素を追加できます。
すべての実装がラップされます。