วิธีแมปนิพจน์แลมบ์ดาใน Java

ฉันมาจาก Python และพยายามทำความเข้าใจว่านิพจน์ lambda ทำงานแตกต่างออกไปใน Java อย่างไร ใน Python คุณสามารถทำสิ่งต่าง ๆ เช่น:

opdict = { "+":lambda a,b: a+b, "-": lambda a,b: a-b, 
           "*": lambda a,b: a*b, "/": lambda a,b: a/b }
sum = opdict["+"](5,4) 

ฉันจะทำสิ่งที่คล้ายกันใน Java ให้สำเร็จได้อย่างไร ฉันได้อ่านมาบ้างแล้วเกี่ยวกับนิพจน์แลมบ์ดาของ Java และดูเหมือนว่าฉันต้องประกาศอินเทอร์เฟซก่อน และฉันก็ไม่ชัดเจนว่าคุณต้องทำเช่นนี้อย่างไรและทำไม

แก้ไข: ฉันพยายามทำสิ่งนี้ด้วยตัวเองด้วยอินเทอร์เฟซที่กำหนดเอง นี่คือรหัสที่ฉันได้ลอง:

Map<String, MathOperation> opMap = new HashMap<String, MathOperation>(){
        { put("+",(a,b)->b+a);
          put("-",(a,b)->b-a);
          put("*",(a,b)->b*a);
          put("/",(a,b)->b/a); }
};
...
...

interface MathOperation {
   double operation(double a, double b);
}

อย่างไรก็ตาม สิ่งนี้ทำให้เกิดข้อผิดพลาด:

ประเภทเป้าหมายของนิพจน์นี้ต้องเป็นอินเทอร์เฟซที่ใช้งานได้

ฉันจะประกาศอินเทอร์เฟซได้ที่ไหน


person b_pcakes    schedule 11.10.2015    source แหล่งที่มา


คำตอบ (2)


ง่ายพอที่จะทำด้วย BiFunction ใน Java 8:

final Map<String, BiFunction<Integer, Integer, Integer>> opdict = new HashMap<>();
opdict.put("+", (x, y) -> x + y);
opdict.put("-", (x, y) -> x - y);
opdict.put("*", (x, y) -> x * y);
opdict.put("/", (x, y) -> x / y);

int sum = opdict.get("+").apply(5, 4);
System.out.println(sum);

ไวยากรณ์มีรายละเอียดมากกว่า Python เล็กน้อย และการใช้ getOrDefault บน opdict น่าจะดีกว่าเพื่อหลีกเลี่ยงสถานการณ์ที่คุณใช้โอเปอเรเตอร์ที่ไม่มีอยู่ แต่อย่างน้อยก็ควรทำให้ลูกบอลกลิ้ง

หากคุณทำงานเฉพาะกับ ints การใช้ IntBinaryOperator จะดีกว่า เนื่องจากจะดูแลการพิมพ์ทั่วไปที่คุณต้องทำ

final Map<String, IntBinaryOperator> opdict = new HashMap<>();
opdict.put("+", (x, y) -> x + y);
opdict.put("-", (x, y) -> x - y);
opdict.put("*", (x, y) -> x * y);
opdict.put("/", (x, y) -> x / y);

int sum = opdict.get("+").applyAsInt(5, 4);
System.out.println(sum);
person Makoto    schedule 11.10.2015
comment
IntBinaryOperatorอาจจะดีขึ้นเล็กน้อย - person Paul Boddington; 12.10.2015
comment
@PaulBoddington: ใช่คุณพูดถูก แต่แล้วเราก็พบกับสถานการณ์ที่น่าอึดอัดใจ: จะเป็นอย่างไรถ้าเราต้องการที่จะเพิ่มสิ่งต่าง ๆ ที่ไม่ใช่แค่ ints เข้าด้วยกัน? ฉันจะรวมสิ่งที่คุณแสดงให้ฉันดูด้วย ขอบคุณสำหรับสิ่งนั้น - person Makoto; 12.10.2015
comment
ใช่แล้ว สถานการณ์แบบนั้นอาจสร้างความรำคาญได้ เมื่อในที่สุดเราได้ Map.of("+", (x, y) -> x + y, "-", ... มันจะสั้นพอๆ กับเวอร์ชัน Python - person Paul Boddington; 12.10.2015
comment
คำตอบที่ดี มีคำถามติดตามเพียงคำถามเดียว ฉันจะทำอย่างไรหากฉันต้องการใช้อินเทอร์เฟซของตัวเอง? ฉันเข้าใจว่าเมื่อคุณสร้างอินสแตนซ์อินเทอร์เฟซโดยใช้นิพจน์แลมบ์ดา โดยพื้นฐานแล้วคุณกำลังนำวิธีนามธรรมของอินเทอร์เฟซไปใช้ โปรดดูการแก้ไขที่ฉันทำกับโพสต์ - person b_pcakes; 12.10.2015
comment
@SimonZhu: ฉันไม่สังเกตเห็นความล้มเหลวในการรวบรวมใด ๆ เมื่อฉันใช้อินเทอร์เฟซที่คุณกำหนดเอง ฉันใช้ Java ล่าสุด (ฉันคิดว่า) ใน 1.8.60; ต้องแน่ใจว่าคุณทันสมัยเช่นกัน - person Makoto; 12.10.2015

ทางเลือกอื่นคือใช้ enum:

public enum Operation {
    PLUS((x, y) -> x + y),
    MINUS((x, y) -> x - y),
    TIMES((x, y) -> x * y),
    DIVIDE((x, y) -> x / y);

    private final IntBinaryOperator op;

    Operation(IntBinaryOperator op) { this.op = op; }

    public int apply(int x, int y) { return op.applyAsInt(x, y); }
}

จากนั้นคุณก็สามารถทำได้:

int sum = Operation.PLUS.apply(5, 4);

สิ่งนี้ไม่กระชับเท่ากับวิธีแก้ปัญหาอื่นๆ แต่การใช้ enum แทน String หมายความว่าเมื่อคุณพิมพ์ Operation. ลงใน IDE คุณจะเห็นรายการการดำเนินการที่เป็นไปได้ทั้งหมด

person Paul Boddington    schedule 11.10.2015