web-dev-qa-db-ja.com

Javaメソッド引数を使用して複数の値を返す必要がありますか?

Javaでメソッドに送信される引数は、呼び出し元メソッドの元のデータ構造を指しているため、Cなどの他の言語の標準と同様に、設計者はそれらを複数の値を返すために使用することを意図していましたか? ?

それとも、これは変数がポインタであるというJavaの一般的なプロパティの危険な誤用ですか?

26
euphoria83

ずっと前に、Ken Arnold(Javaチームの1回のメンバー)と会話しました。これは最初のJava 1つの会議でした。 、だから1996年。彼はあなたが次のようなものを書くことができるように複数の戻り値を追加することを考えていると言った:

x, y = foo();

当時および現在の推奨される方法は、複数のデータメンバーを持つクラスを作成し、代わりにそれを返すことです。

それと、Javaに携わった人々からのその他のコメントに基づいて、渡された引数を変更するのではなく、クラスのインスタンスを返すことが意図されていると思います。

これは一般的な方法です(Cプログラマーが引数を変更したいという願望があるように...最終的にはJava通常の方法です。構造体を返すと考えてください。:- )

(以下のコメントに基づいて編集)

私はファイルを読み取り、String型とint型の2つの配列を生成し、各行から両方の要素を1つ選択しています。この方法で分割するファイルを呼び出す関数に両方を返したいと思います。

私があなたを正しく理解しているなら、私はおそらくこのようなことをするだろうと思います:

// could go with the Pair idea from another post, but I personally don't like that way
class Line
{
    // would use appropriate names
    private final int intVal;
    private final String stringVal;

    public Line(final int iVal, final String sVal)
    {
        intVal    = iVal;
        stringVal = sVal;
    }

    public int getIntVal()
    {
        return (intVal);
    }

    public String getStringVal()
    {
        return (stringVal);
    }

    // equals/hashCode/etc... as appropriate
}

次に、次のようなメソッドを使用します。

public void foo(final File file, final List<Line> lines)
{
    // add to the List.
}

そしてそれをこのように呼びます:

{
    final List<Line> lines;

    lines = new ArrayList<Line>();
    foo(file, lines);
}
15
TofuBeer

私の意見では、パブリックメソッドについて話している場合は、戻り値を表す別のクラスを作成する必要があります。別のクラスがある場合:

  • 抽象化として機能します(つまり、2つのlongの配列ではなくPointクラス)
  • 各フィールドには名前があります
  • 不変にすることができます
  • aPIの進化がはるかに簡単になります(つまり、2つの値ではなく3つの値を返す、一部のフィールドのタイプを変更するなど)

渡された値を実際に変更するのではなく、常に新しいインスタンスを返すことを選択します。それは私にははるかに明確であり、不変性を支持します。

一方、内部メソッドの場合は、次のいずれかが使用される可能性があると思います。

  • 配列(_new Object[] { "str", longValue }_)
  • リスト(Arrays.asList(...)は不変のリストを返します)
  • this などのペア/タプルクラス
  • パブリックフィールドを持つ静的内部クラス

それでも、適切なコンストラクターを備えた最後のオプションをお勧めします。これは、同じタプルを複数の場所から返す場合に特に当てはまります。

7
javashlook

主にこの理由で、JDKにPair<E,F>クラスがあったらいいのにと思います。 Map<K,V>.Entryがありますが、インスタンスの作成は常に大きな苦痛でした。

Pairが必要なときにcom.google.common.collect.Maps.immutableEntryを使用するようになりました

5

1999年に立ち上げられたこのRFEを参照してください。

http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=4222792

Java言語でそれを許可するつもりはなかったと思います。複数の値を返す必要がある場合は、それらをオブジェクトにカプセル化する必要があります。

Scalaのような言語を使用しますが、タプルを返すことができます。以下を参照してください。

http://www.artima.com/scalazine/articles/steps.html

Javaでジェネリックスを使用してオブジェクトのペアを返すこともできますが、それはAFAIKについてです。

編集:タプル

これにもう少し追加するだけです。 JDKが不足しているため、以前はプロジェクトにペアを実装しました。私の実装へのリンクはここにあります:

http://pbin.oogly.co.uk/listings/viewlistingdetail/5003504425055b47d857490ff73ab9

これにはハッシュコードまたは同等のものがないことに注意してください。おそらく追加する必要があります。

また、タプル機能を提供するこの質問について調査しているときに、これに遭遇しました。

http://javatuple.com/

他のタイプのタプルを含むペアを作成できます。

5
Jon

本当に複数の値を返すことはできませんが、canオブジェクトをメソッドに渡し、メソッドにそれらの値を変更させることができます。それは完全に合法です。オブジェクトを渡して、オブジェクト自体を別のオブジェクトにすることはできないことに注意してください。あれは:

_private void myFunc(Object a) {
    a = new Object();
}
_

temporaryおよびlocallyaですが、これによって呼び出し元の値が変更されることはありません。たとえば、次のようになります。

_Object test = new Object();
myFunc(test);
_

MyFuncが戻ると、oldオブジェクトが作成され、新しいオブジェクトは作成されません。

法的な(そしてしばしば落胆する)のは次のようなものです:

_private void changeDate(final Date date) {
    date.setTime(1234567890L);
}
_

理由でDateを選びました。これは、人々が広く同意するクラスであり、変更可能であってはなりません。上記のメソッド、渡されたDateオブジェクトの内部値を変更します。この種のコードは、メソッドが渡されるものを変更、構成、または変更することが非常に明確な場合に合法です。

注:一般的に、メソッドは次のいずれかを実行する必要があると言われています。

  • Voidを返し、その着信オブジェクト(Collections.sort()など)を変更するか、または
  • いくつかの計算を返し、着信オブジェクトをまったく変更しない(Collections.min()など)、または
  • 着信オブジェクトの「ビュー」を返しますが、着信オブジェクトは変更しないでください(Collections.checkedList()Collections.singleton()など)
  • 1つの着信オブジェクトを変更して返します(Collectionsには例がありませんが、StringBuilder.append()が良い例です)。

着信オブジェクトを変更するメソッドおよびが個別の戻り値を返すメソッドは、多くの場合、多くのことを実行します。

2
Eddie

パラメータとして渡されたオブジェクトを変更するメソッドは確かにあります( 例としてJava.io.Reader.read(byte [] buffer) を参照)が、の代わりに使用されるパラメータを見たことがありません。特に複数のパラメータがある場合の戻り値。技術的には機能する可能性がありますが、非標準です。

0
Nathan Voxland

これは一般的にひどく良い習慣とは考えられていませんが、これが行われるJDKでは非常にまれなケースがあります。 View.getNextVisualPositionFrom()の「biasRet」パラメーターと関連するメソッドを見てください。たとえば、これは実際には「追加の戻り値」で埋められる1次元配列です。

では、なぜこれを行うのですか?さて、あなたを救うために、「時折余分な戻り値」のための余分なクラス定義を作成する必要があります。それは乱雑で、エレガントでなく、デザインが悪く、オブジェクト指向ではなく、何とか何とかです。そして、私たちは皆、時々それをしました...

0
Neil Coffey

メソッドパラメータとして一連の検証voidメソッドをカスケードするResultオブジェクトがありました。これらの検証voidメソッドはそれぞれ、結果パラメーターオブジェクトを変更して、検証の結果を追加します。

ただし、voidメソッドをスタブして、Resultオブジェクトの検証用のスタブ値を返すことができないため、これをテストすることはできません。

したがって、テストの観点からは、メソッドパラメータを変更するのではなく、オブジェクトを返す方がよいように思われます。

0
sudr

一般的にエディが言ったことですが、もう1つ追加します。

  • 着信オブジェクトの1つを変更し、ステータスコードを返します。これは通常、Reader.read(char [] cbuf)のように、明示的にバッファーである引数にのみ使用する必要があります。
0
Kevin Peterson