18

可変引数を期待するメソッドに文字列と文字列配列を渡す簡単でエレガントで再利用可能な方法があるかどうか疑問に思っています。

/**
 * The entry point with a clearly separated list of parameters.
 */
public void separated(String p1, String ... p2) {
    merged(p1, p2, "another string", new String[]{"and", "those", "one"});
}

/**
 * For instance, this method outputs all the parameters.
 */
public void merged(String ... p) {
    // magic trick
}

すべてのタイプが一貫している場合でも ( String)、JVM にp2を平坦化し、マージされたパラメーター リストに挿入するように指示する方法が見つかりませんか?

この時点で唯一の方法は、新しい配列を作成し、すべてをコピーして関数に渡すことです。

何か案が?


編集

ここでのあなたの提案に基づいて、私が使用する一般的な方法があります:

/**
 * Merge the T and T[] parameters into a new array.
 *
 * @param type       the destination array type
 * @param parameters the parameters to merge
 * @param <T>        Any type
 * @return the new holder
 */
@SuppressWarnings("unchecked")
public static <T> T[] normalize(Class<T> type, Object... parameters) {
    List<T> flatten = new ArrayList<>();
    for (Object p : parameters) {
        if (p == null) {
            // hum... assume it is a single element
            flatten.add(null);
            continue;
        }
        if (type.isInstance(p)) {
            flatten.add((T) p);
            continue;
        }
        if (p.getClass().isArray() && 
            p.getClass().getComponentType().equals(type)) {
            Collections.addAll(flatten, (T[]) p);
        } else {
            throw new RuntimeException("should be " + type.getName() + 
                                             " or " + type.getName() + 
                                             "[] but was " + p.getClass());
        }
    }
    return flatten.toArray((T[]) Array.newInstance(type, flatten.size()));
}

normalize(String.class, "1", "2", new String[]{"3", "4", null}, null, "7", "8");
4

6 に答える 6

6

スカラーと配列を暗黙的に単一の配列にフラット化する方法はないと思います。

私が考えることができる最もクリーンな解決策は、ヘルパー関数を使用することです:

// generic helper function
public static<T> T[] join(T scalar, T[] arr) {
    T[] ret = Arrays.copyOfRange(arr, 0, arr.length + 1);
    System.arraycopy(ret, 0, ret, 1, arr.length);
    ret[0] = scalar;
    return ret;
}

public void separated(String p1, String ... p2) {
    merged(join(p1, p2));
}
于 2013-03-12T09:41:36.590 に答える
2

の署名を次のように変更しますmerge

public<T> void merged(T ... p) 

少なくとも問題なくマージを呼び出すことができます。ただし、文字列の配列をパラメーターとして処理する必要があります。

于 2013-03-12T09:41:39.930 に答える
0

内ではseparated、パラメータp2String[]です。このmergedメソッドは、単一のパラメーターまたは文字列のシーケンスのいずれかを取ることができますが、2つの混合はできません。したがって、新しい配列を作成する以外に多くのオプションはないと思います(varargsが舞台裏で行うことです)。String[]

于 2013-03-12T09:46:55.290 に答える
0

varargsdocから

最終パラメータの型の後の3つのピリオドは、最終引数が配列または引数のシーケンスとして渡される可能性があることを示します。

それは明確に述べているan array OR a sequence of argumentsので、例えばNPEによって提案されているように、自分でアレイをフラット化する必要があります。

于 2013-03-12T09:47:16.973 に答える
0

あなたがそれを行うことができるとは思えませんが、Javaコンパイラはmerged(p1、p2)をmerged(p1、p2 [0]、p2 [1] ... p2 [p2.length])に変換する必要がありますが、私はそれらを考えていませんこのようなスマートコンパイラを作成したいと思ったことはありません(マージされた(p1、p2)も存在する場合は問題が発生します)。

代わりにこれを行うことができます(疑似構文を使用):

import com.google.common.collect.Lists
import java.util.Arrays

separated ( String p1, String... p2 ) {
  merged ( Lists.asList ( p1, p2 ) )
}

merged ( List<String> p ) {
...
}

merged ( String ... p ) {
  merged ( Arrays.asList ( p )
}

配列は標準のJDKからのものであり、リストはGuavaからのものです。どちらのasList()メソッドも、コピーではなく、下線を引く配列のビューを作成するため、速度やメモリに関する懸念はあまりありません。

より単純なアプローチは存在しないと思います。はい、他の人が提案しているように、新しいアレイにコピーする方が簡単ですが、時間とメモリを消費します。配列が小さい場合は、リストの作成とアクセスがコピーよりも遅くなる可能性がありますが、配列が大きい場合は、コピーのオーバーヘッドが高くなります。

Sebastianの提案が好きです。フライト中の配列をフラット化するmerge()のラッパーを定義します。これは、merge()がサードパーティのメソッドではなく、変更できる限り、うまく機能します。そうでなければ、私はここで似たようなことをしています。

于 2013-03-12T10:07:54.670 に答える
0

新しい配列を作成することが道だと思います。

たとえば、それを実現するためにApache CommonsArrayUtilsから使用できます。

ArrayUtils.addAll(p2, p1);

よろしく、 トーマス

于 2013-03-12T09:40:46.140 に答える