เหตุใดฉันจึงไม่สามารถแมปเลขจำนวนเต็มกับสตริงเมื่อสตรีมจากอาร์เรย์ได้


95

รหัสนี้ใช้งานได้ (ถ่ายใน 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 บอกฉันว่าฉันมี "สตริงประเภทการส่งคืนที่ไม่เข้ากันในนิพจน์แลมบ์ดา"

ทำไม? และจะแก้ไขอย่างไร?

คำตอบ:


122

Arrays.stream(int[])สร้างIntStreamไม่ใช่Stream<Integer>. ดังนั้นคุณต้องเรียกmapToObjแทน just mapเมื่อแมป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

8
@FlorianMargaine An IntStreamเป็นสตรีมเฉพาะทางสำหรับintค่าดั้งเดิม A Stream<Integer>เป็นเพียง Stream ถือIntegerวัตถุ
Alexis C.

2
@FlorianMargaine IntStreamเป็นกระแสหรือแบบดั้งเดิม (ints) ในขณะที่Steram<Integer>กระแสของวัตถุ กระแสดั้งเดิมมีวิธีการพิเศษสำหรับเหตุผลด้านประสิทธิภาพ
assylias

7
IntStream.mapToObjคาดหวังว่าIntFunctionฟังก์ชันที่ใช้intค่าดังนั้นจึง  .mapToObj((Integer i) -> i.toString())ไม่ทำงาน มันจะไม่ได้รับการแนะนำอยู่แล้วเนื่องจากมีการแปลงไม่จำเป็นออกจากการint Integerในทางตรงกันข้ามการ.mapToObj(Integer::toString)ทำงานอย่างเป็นมันจะเรียกวิธีการstatic Integer.toString(int)โปรดทราบว่าสิ่งนี้แตกต่างจากการเรียก.map(Integer::toString)ใช้ a  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โดยตรง

ข้อดีคือmapToObjไม่ต้องใส่intค่าแต่ละค่าให้กับIntegerวัตถุ ขึ้นอยู่กับฟังก์ชันการทำแผนที่ที่คุณใช้แน่นอน ดังนั้นฉันจะใช้ตัวเลือกนี้ซึ่งสั้นกว่าในการเขียน


5

คุณสามารถสร้าง Integer Stream โดยใช้ 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

หากจุดประสงค์ของตัวอย่างและคำถามนี้คือการหาวิธีแมปสตริงกับสตรีมของ ints (ตัวอย่างเช่นการใช้สตรีม 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 ของคุณ (สตรีมของ Ints ดั้งเดิม) ของคุณเป็นสตรีม (สตรีมของอ็อบเจ็กต์ - คืออ็อบเจ็กต์จำนวนเต็ม) ซึ่งจะยอมรับการส่งคืนอ็อบเจ็กต์ (ในกรณีนี้คืออ็อบเจกต์ String) จาก แลมด้าของคุณ นี่เป็นเพียงการแสดงสตริงของตัวเลขเพื่อจุดประสงค์ในการสาธิต แต่อาจเป็นวัตถุสตริงใด ๆ ก็ได้ (และในทางปฏิบัติมากกว่า) เช่นเดียวกับองค์ประกอบของสตริงอาร์เรย์ตามที่กล่าวไว้ก่อนหน้านี้

แค่คิดว่าฉันเสนอความเป็นไปได้อื่น ในการเขียนโปรแกรมมีหลายวิธีในการทำงานให้สำเร็จ รู้ให้มากที่สุดจากนั้นเลือกสิ่งที่เหมาะกับงานที่ทำมากที่สุดโดยคำนึงถึงปัญหาด้านประสิทธิภาพการใช้งานง่ายความชัดเจนของโค้ดความชอบของคุณในรูปแบบการเข้ารหัสและการจัดทำเอกสารด้วยตนเองมากที่สุด

ขอให้สนุกกับการเขียนโค้ด!


1
คุณกำลังทำงานที่ไม่จำเป็น คุณใส่กล่องแต่ละintประเภทเป็นชนิดกระดาษห่อหุ้มIntegerและแกะกล่องหลังจากนั้น
Alexis C.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.