Java: มีฟังก์ชั่นแผนที่หรือไม่?


140

ฉันต้องการ ฟังก์ชั่นแผนที่ มีบางอย่างเช่นนี้ใน Java อยู่แล้ว?

(สำหรับผู้ที่สงสัยว่า: แน่นอนฉันรู้วิธีการใช้ฟังก์ชั่นเล็กน้อยนี้เอง ... )


1
ถ้าไม่เป็นเรื่องเล็กน้อยที่จะนิยามตัวเอง แต่ฉันคิดว่า google รู้การใช้งานโหล?

2
ทำซ้ำ (ค่อนข้างดีกว่า) ที่stackoverflow.com/questions/3907412/…
Chowlett

6
@ Chris: มันเป็นคำถามเดียวกันได้อย่างไร
อัลเบิร์

1
หากคำตอบของคำถามนี้คือใช่คำตอบนั้นก็คือคำถามที่เชื่อมโยงอื่น ๆ ด้วย หากคำตอบคือไม่ (และดูเหมือนว่า) พวกเขาจะไม่เกี่ยวข้องอย่างสมบูรณ์
อัลเบิร์

1
ในฐานะของ Java8, นี่คือสิ่งที่ @delnan อาจถูกอ้างถึง leveluplunch.com/java/examples/ …
Eternalcode

คำตอบ:


86

ไม่มีความคิดของฟังก์ชั่นใน JDK เป็นของ java 6

Guavaมีส่วนต่อประสานฟังก์ชั่นและ วิธีการใช้งานที่คุณต้องการ
Collections2.transform(Collection<E>, Function<E,E2>)

ตัวอย่าง:

// example, converts a collection of integers to their
// hexadecimal string representations
final Collection<Integer> input = Arrays.asList(10, 20, 30, 40, 50);
final Collection<String> output =
    Collections2.transform(input, new Function<Integer, String>(){

        @Override
        public String apply(final Integer input){
            return Integer.toHexString(input.intValue());
        }
    });
System.out.println(output);

เอาท์พุท:

[a, 14, 1e, 28, 32]

ทุกวันนี้ด้วย Java 8 มีฟังก์ชั่นแผนที่อยู่จริงดังนั้นฉันอาจจะเขียนโค้ดด้วยวิธีที่กระชับกว่านี้:

Collection<String> hex = input.stream()
                              .map(Integer::toHexString)
                              .collect(Collectors::toList);

8
เป็นที่น่าสังเกตว่าในขณะที่ใช้ Guava คุณสามารถทำได้คุณอาจไม่ต้องการ: code.google.com/p/guava-l ไลบรารี/wiki/FunctionalExplained (อ่านส่วน "Caveats")
Adam Parkin

2
@ AdamParkin จริง แต่ฉันค่อนข้างแน่ใจว่าหมายถึงแนวคิดการทำงานขั้นสูงกว่านี้มิฉะนั้นพวกเขาจะไม่ได้พัฒนาวิธีการแปลง ( ) ในสถานที่แรก
Sean Patrick Floyd

2
ที่จริงแล้วไม่มักจะมีการตีที่แน่นอนกับสำนวนการทำงานซึ่งเป็นเหตุผลที่พวกเขาเน้นที่คุณควรใช้สิ่งอำนวยความสะดวกถ้าคุณมีบางอย่างที่มันเป็นไปตามสองเกณฑ์ที่ระบุไว้: ออมสุทธิของ LOC สำหรับ codebase โดยรวมและการพิสูจน์ประสิทธิภาพเพิ่มขึ้นเนื่องจากการประเมินผลที่ขี้เกียจ ไม่โต้เถียงกับการใช้งานของพวกเขาเพียงแค่ระบุว่าถ้าคุณจะไปคุณควรฟังคำเตือนของผู้ใช้งาน
Adam Parkin

4
@SeanPatrickFloyd ตอนนี้ Java 8 ออกแล้วต้องการอัปเดตสิ่งนี้ด้วยตัวอย่างที่เกี่ยวข้องกับ lambdas หรือไม่? ชอบCollections2.transform(input -> Integer.toHexString(intput.intValue())
แดเนียล Lubarov

2
@Daniel ใน Java 8 ฉันไม่เห็นเหตุผลที่จะทำเช่นนั้นกับ Guava แต่ฉันจะไปหาคำตอบของ leventov
ฌอนแพทริคฟลอยด์

92

ตั้งแต่ Java 8 มีตัวเลือกมาตรฐานให้ทำใน JDK:

Collection<E> in = ...
Object[] mapped = in.stream().map(e -> doMap(e)).toArray();
// or
List<E> mapped = in.stream().map(e -> doMap(e)).collect(Collectors.toList());

ดู java.util.Collection.stream()java.util.stream.Collectors.toList()และ


140
นี่คือ verbose มากที่เจ็บฉันภายใน
Natix

1
@Natix toList()ตกลงเกี่ยวกับ เปลี่ยนเป็นประเภทอื่น:(List<R>)((List) list).replaceAll(o -> doMap((E) o));
leventov

2
สามารถe -> doMap(e)ถูกแทนที่ด้วยเพียงdoMap?
jameshfisher

3
@jameshfisher ใช่สิ่งที่ต้องการหรือfoo::doMap Foo::doMap
leventov

9
ฉันเดาว่านี่เป็นเหตุผลที่สกาล่ามีอยู่จริง รอให้ Java 12 มีบางอย่างที่อ่านได้
JulienD

26

มีไลบรารีที่ยอดเยี่ยมที่เรียกว่าFunctional Javaซึ่งจัดการหลายสิ่งที่คุณต้องการให้ Java มี แต่มันไม่มี จากนั้นอีกครั้งมี Scala ภาษาที่ยอดเยี่ยมนี้ซึ่งทำทุกสิ่งที่ Java ควรทำ แต่ไม่ได้ในขณะที่ยังเข้ากันได้กับสิ่งที่เขียนขึ้นสำหรับ JVM


ฉันสนใจว่าพวกเขาเปิดใช้งานไวยากรณ์ต่อไปนี้: a.map({int i => i + 42});พวกเขาขยายคอมไพเลอร์หรือไม่? หรือเพิ่มโปรเซสเซอร์ล่วงหน้า?
Andrey

@Andrey - คุณสามารถถามพวกเขาด้วยตัวคุณเองหรือลองดูซอร์สโค้ดเพื่อดูว่ามันเสร็จสิ้นแล้ว นี่คือลิงค์ไปยังแหล่งที่มา: functionaljava.org/source
วี

1
@Andrey: ตัวอย่างใช้ไวยากรณ์จากข้อเสนอการปิด BGGA ในขณะที่มีการรันต้นแบบมันยังไม่ได้อยู่ใน Java 'เป็นทางการ'
ปีเตอร์Štibraný

@Andrey: ไวยากรณ์นั้นเป็นส่วนหนึ่งของข้อกำหนดที่เสนอสำหรับการปิดใน Java (ดูย่อหน้าที่สองถึงครั้งสุดท้ายในหน้าแรก) มีเพียงการนำต้นแบบไปปฏิบัติ
Michael Borgwardt

2
Scala thread hijack :( ฉันหวังว่า SO จะไม่กลายเป็นรายการส่งเมล JavaPosse;)
Jorn

9

ระวังด้วยCollections2.transform()จากฝรั่ง ความได้เปรียบที่ยิ่งใหญ่ที่สุดของวิธีการนั้นก็เป็นอันตรายที่ยิ่งใหญ่เช่นกัน

ดูเอกสารของLists.transform()ซึ่งฉันเชื่อว่าใช้กับCollections2.transform():

ฟังก์ชั่นนี้ใช้งานได้อย่างเกียจคร้านเมื่อถูกเรียกใช้ นี่เป็นสิ่งจำเป็นสำหรับรายการที่ส่งคืนเพื่อเป็นมุมมอง แต่หมายความว่าฟังก์ชันจะถูกนำไปใช้หลายครั้งสำหรับการดำเนินการจำนวนมากเช่น List.contain (java.lang.Object) และ List.hashCode () เพื่อให้ทำงานได้ดีฟังก์ชั่นควรเร็ว เพื่อหลีกเลี่ยงการประเมินที่ขี้เกียจเมื่อรายการที่ส่งคืนไม่จำเป็นต้องเป็นมุมมองให้คัดลอกรายการที่ส่งคืนไปยังรายการใหม่ที่คุณเลือก

นอกจากนี้ในเอกสารประกอบของCollections2.transform()พวกเขาพูดถึงคุณได้รับมุมมองสดการเปลี่ยนแปลงในรายการแหล่งที่มามีผลต่อรายการเปลี่ยนแปลง พฤติกรรมประเภทนี้อาจนำไปสู่ปัญหาที่ยากต่อการติดตามหากนักพัฒนาซอฟต์แวร์ไม่เข้าใจวิธีการทำงาน

หากคุณต้องการ "แผนที่" แบบคลาสสิกยิ่งขึ้นนั่นจะทำงานเพียงครั้งเดียวเท่านั้นคุณก็จะดีขึ้นด้วยFluentIterableเช่นกันจาก Guava ซึ่งมีการใช้งานที่ง่ายกว่ามาก นี่คือตัวอย่างของ google มัน:

FluentIterable
       .from(database.getClientList())
       .filter(activeInLastMonth())
       .transform(Functions.toStringFunction())
       .limit(10)
       .toList();

transform()นี่คือวิธีการแผนที่ จะใช้ฟังก์ชั่นเดียวกัน <> "เรียกกลับ" Collections.transform()เป็น รายการที่คุณได้รับกลับมาเป็นแบบอ่านอย่างเดียว แต่ใช้copyInto()เพื่อรับรายการอ่าน - เขียน

มิฉะนั้นแน่นอนเมื่อ java8 ออกมาพร้อมกับ lambdas สิ่งนี้จะล้าสมัย



2

แม้ว่าจะเป็นคำถามเก่าที่ฉันต้องการแสดงวิธีแก้ไขปัญหาอื่น:

เพียงกำหนดการทำงานของคุณเองโดยใช้ java generics และ java 8 stream:

public static <S, T> List<T> map(Collection<S> collection, Function<S, T> mapFunction) {
   return collection.stream().map(mapFunction).collect(Collectors.toList());
}

คุณสามารถเขียนโค้ดดังนี้:

List<String> hex = map(Arrays.asList(10, 20, 30, 40, 50), Integer::toHexString);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.