配列からストリーミングするときに整数を文字列にマッピングできないのはなぜですか?


92

このコードは動作します(Javadocで取得):

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
    .map(i -> i.toString())
    .collect(Collectors.joining(", "));

これはコンパイルできません:

int[] numbers = {1, 2, 3, 4};
String commaSeparatedNumbers = Arrays.stream(numbers)
    .map((Integer i) -> i.toString())
    .collect(Collectors.joining(", "));

IDEAは、「ラムダ式の互換性のない戻り値の型文字列」があることを教えてくれます。

どうして ?そしてそれを修正するには?

回答:


114

Arrays.stream(int[])IntStreamではなくを作成しますStream<Integer>。したがって、をオブジェクトにマッピングするときmapToObjmap、の代わりにを呼び出す必要がありintます。

これは期待どおりに機能するはずです。

String commaSeparatedNumbers = Arrays.stream(numbers)
    .mapToObj(i -> ((Integer) i).toString()) //i is an int, not an Integer
    .collect(Collectors.joining(", "));

これも書くことができます:

String commaSeparatedNumbers = Arrays.stream(numbers)
    .mapToObj(Integer::toString)
    .collect(Collectors.joining(", "));

3
違いは何だIntStreamとはStream<Integer>
Florian Margaine、2015年

8
@FlorianMargaine An IntStreamは、プリミティブint値のストリーム特殊化です。A Stream<Integer>Integerオブジェクトを保持する単なるストリームです。
Alexis C.

2
@FlorianMargaine IntStreamはストリームまたはプリミティブ(int)Steram<Integer>ですが、オブジェクトのストリームです。プリミティブストリームには、パフォーマンス上の理由から特別な方法があります。
アッシリアス

7
IntStream.mapToObjは値  IntFunctionを消費する関数であるため、機能しません。からへの不要な変換が含まれているため、いずれにしてもお勧めしません。対照的に、メソッドを呼び出すのでうまく機能します。あいまいであるため、後者はコンパイルされないため、これはaの  呼び出しとは異なります。int.mapToObj((Integer i) -> i.toString())intInteger.mapToObj(Integer::toString)staticInteger.toString(int).map(Integer::toString)Stream<Integer>
Holger

1
@cic:いいえ、.map(Integer::toString)aを呼び出すことStream<Integer>は両方として本当にあいまいで.map(i->i.toString())あり.map(i->Integer.toString(i))、有効です。ただし、を使用すると簡単に解決でき.map(Object::toString)ます。
Holger

19

Arrays.stream(numbers)IntStreamボンネットの下にを作成し、に対するマップ操作をIntStream要求しますIntUnaryOperator(つまり、関数int -> int)。適用するマッピング関数はこの規約を尊重せず、したがってコンパイルエラーが発生します。

boxed()を取得するには、前に呼び出す必要がありますStream<Integer>(これがArrays.asList(...).stream()戻ります)。次にmap、最初のスニペットと同じように呼び出します。

あなたがboxed()フォローする必要がある場合は、mapおそらくmapToObj直接使用したいことに注意してください。

利点は、mapToObjint値をIntegerオブジェクトにボックス化する必要がないことです。もちろん、適用するマッピング関数によって異なります。だから私はこのオプションも使うでしょう。


5

あなたはArrays.stream(int型[])を使用して、整数ストリームを作成することができ、あなたが呼び出すことができますmapToObjようにmapToObj(Integer::toString)

String csn = Arrays.stream(numbers) // your numbers array
.mapToObj(Integer::toString)
.collect(Collectors.joining(", "));

お役に立てれば..


2

ボクシング、AFAIK、およびヒープに追加された小さな文字列の爆発はありません。

public static void main(String[] args) {
    IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6);
    String s = stream.collect(StringBuilder::new, (builder, n) -> builder.append(',').append(n), (x, y) -> x.append(',').append(y)).substring(1);
    System.out.println(s);
}

1

このサンプルと質問の目的が文字列をintのストリームにマップする方法を理解することである場合(たとえば、intのストリームを使用して文字列の配列のインデックスにアクセスする)、ボクシングを使用してキャストすることもできますint(これにより、配列のインデックスへのアクセスが可能になります)。

int[] numbers = {0, 1, 2, 3}; 
String commaSeparatedNumbers = Arrays.stream(numbers)
    .boxed()
    .map((Integer i) -> Integer.toString((int)i))
    .collect(Collectors.joining(", "));

.boxed()呼び出しは、IntStream(プリミティブintのストリーム)をStream(オブジェクトのストリーム、つまりIntegerオブジェクト)に変換し、それからオブジェクト(この場合はStringオブジェクト)の戻りを受け入れます。あなたのラムダ。ここでは、デモンストレーション用の数値の単なる文字列表現ですが、前述の文字列配列の要素のように、任意の文字列オブジェクトにすることも同じくらい簡単に(より実用的に)できます。

私は別の可能性を提供すると思いました。プログラミングでは、タスクを実行する方法が常に複数あります。できる限り多くを把握し、パフォーマンスの問題、直感性、コードの明確さ、コーディングスタイルの好み、および最も自己文書化を念頭に置いて、目前のタスクに最適なものを選択してください。

幸せなコーディング!


1
あなたは不必要な仕事をしています。それぞれintをラッパータイプにボックス化し、Integer直後にボックス化解除します。
Alexis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.