java lambda สามารถมีพารามิเตอร์มากกว่า 1 ตัวได้หรือไม่?


157

ใน Java เป็นไปได้ไหมที่แลมบ์ดาจะยอมรับหลายประเภทที่แตกต่างกัน?

เช่น: ตัวแปรเดียวทำงาน:

    Function <Integer, Integer> adder = i -> i + 1;
    System.out.println (adder.apply (10));

Varargs ยังทำงานได้:

    Function <Integer [], Integer> multiAdder = ints -> {
        int sum = 0;
        for (Integer i : ints) {
            sum += i;
        }
        return sum;
    };

    //.... 
    System.out.println ((multiAdder.apply (new Integer [] { 1, 2, 3, 4 })));

แต่ฉันต้องการบางสิ่งที่สามารถยอมรับข้อโต้แย้งหลายประเภทเช่น:

    Function <String, Integer, Double, Person, String> myLambda = a , b, c, d->  {
    [DO STUFF]
    return "done stuff"
    };

การใช้งานหลักคือการมีฟังก์ชั่นอินไลน์เล็ก ๆ ภายในฟังก์ชั่นเพื่อความสะดวก

ฉันมองไปรอบ ๆ google และตรวจสอบ Function Package ของ Java แล้ว แต่หาไม่เจอ เป็นไปได้ไหม

คำตอบ:


178

เป็นไปได้ถ้าคุณกำหนดอินเทอร์เฟซที่ใช้งานได้ด้วยพารามิเตอร์หลายประเภท ไม่มีประเภทในตัวดังกล่าว (มีข้อ จำกัด บางประเภทที่มีพารามิเตอร์หลายตัว)

@FunctionalInterface
interface Function6<One, Two, Three, Four, Five, Six> {
    public Six apply(One one, Two two, Three three, Four four, Five five);
}

public static void main(String[] args) throws Exception {
    Function6<String, Integer, Double, Void, List<Float>, Character> func = (a, b, c, d, e) -> 'z';
}

ฉันเรียกมันว่าFunction6ที่นี่ ชื่อขึ้นอยู่กับดุลยพินิจของคุณเพียงพยายามอย่าปะทะกับชื่อที่มีอยู่ในไลบรารี Java


นอกจากนี้ยังไม่มีวิธีกำหนดจำนวนพารามิเตอร์ประเภทตัวแปรหากนั่นคือสิ่งที่คุณถาม


บางภาษาเช่น Scala กำหนดจำนวนบิวด์อินชนิดดังกล่าวโดยมีพารามิเตอร์ประเภท 1, 2, 3, 4, 5, 6, ฯลฯ


58
คุณสามารถใช้ Currying ได้ตลอดเวลา:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger

@SotiriosDelimanolis: ฉันควรเลือกชื่ออื่นFunctionที่ขัดแย้งกับชื่อjava.util.function.Function<T,R>นั้นอาจไม่ชัดเจนสำหรับผู้เริ่มต้น
Nikolas

@ Nikolas นั่นสมเหตุสมผล แก้ไข
Sotirios Delimanolis

39

สำหรับบางสิ่งบางอย่างที่มี 2 BiFunctionพารามิเตอร์คุณสามารถใช้ หากคุณต้องการมากกว่านี้คุณสามารถกำหนดฟังก์ชั่นการใช้งานของคุณเองเช่น:

@FunctionalInterface
public interface FourParameterFunction<T, U, V, W, R> {
    public R apply(T t, U u, V v, W w);
}

หากมีมากกว่าหนึ่งพารามิเตอร์คุณต้องใส่วงเล็บไว้รอบรายการอาร์กิวเมนต์ดังนี้:

FourParameterFunction<String, Integer, Double, Person, String> myLambda = (a, b, c, d) -> {
    // do something
    return "done something";
};

34

สำหรับกรณีนี้คุณสามารถใช้อินเตอร์เฟสจากไลบรารีเริ่มต้น (java 1.8):

java.util.function.BiConsumer
java.util.function.BiFunction

มีตัวอย่างเล็ก ๆ (ไม่ดีที่สุด) ของวิธีการเริ่มต้นในส่วนต่อประสาน:

default BiFunction<File, String, String> getFolderFileReader() {
    return (directory, fileName) -> {
        try {
            return FileUtils.readFile(directory, fileName);
        } catch (IOException e) {
            LOG.error("Unable to read file {} in {}.", fileName, directory.getAbsolutePath(), e);
        }
        return "";
    };
}}

5
คุณจะได้รับคะแนนโหวตมากขึ้นจากแฟน ๆ Java8 หากคุณแก้ไขคำถามของคุณเพื่อแสดงให้เห็นว่าอินเทอร์เฟซเหล่านั้นสามารถนำมาใช้เพื่อตอบสนองความต้องการได้อย่างไร
Martin Cowie

3
BiFunction ช่วยให้คุณสามารถกำหนดฟังก์ชั่นสองอาร์กิวเมนต์เท่านั้น, คำถามเกี่ยวกับฟังก์ชั่นที่มีจำนวนของอาร์กิวเมนต์ใด ๆ
Dmitry Klochkov

8

ในการใช้แลมบ์ดา: มีสามประเภทของการดำเนินงาน:
1. ยอมรับพารามิเตอร์ -> ผู้บริโภค
2. ทดสอบพารามิเตอร์บูลีน -> ภาคแสดง
3. จัดการพารามิเตอร์และส่งคืนค่า -> ฟังก์ชั่น

Java อินเตอร์เฟซที่ทำงานไม่เกินสองพารามิเตอร์:
พารามิเตอร์เดี่ยวอินเตอร์เฟซ
ผู้บริโภค
กริยา
ฟังก์ชั่น

สองพารามิเตอร์อินเตอร์เฟซ
BiConsumer
BiPredicate
BiFunction

สำหรับมากกว่าสองคุณต้องสร้างอินเตอร์เฟสที่ใช้งานได้ดังต่อไปนี้ (ประเภทผู้บริโภค):

@FunctionalInterface
public interface FiveParameterConsumer<T, U, V, W, X> {
    public void accept(T t, U u, V v, W w, X x);
}

1

ทางเลือกอื่นไม่แน่ใจว่าสิ่งนี้จะนำไปใช้กับปัญหาเฉพาะของคุณ แต่สำหรับบางคนมันอาจจะใช้ได้คือการใช้UnaryOperatorในไลบรารี java.util.function โดยที่มันจะคืนค่าชนิดเดียวกันกับที่คุณระบุดังนั้นคุณจึงใส่ตัวแปรทั้งหมดของคุณไว้ในคลาสเดียวและมันเป็นพารามิเตอร์:

public class FunctionsLibraryUse {

    public static void main(String[] args){
        UnaryOperator<People> personsBirthday = (p) ->{
            System.out.println("it's " + p.getName() + " birthday!");
            p.setAge(p.getAge() + 1);
            return p;
        };
        People mel = new People();
        mel.setName("mel");
        mel.setAge(27);
        mel = personsBirthday.apply(mel);
        System.out.println("he is now : " + mel.getAge());

    }
}
class People{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

ดังนั้นคลาสที่คุณมีในกรณีนี้Personอาจมีตัวแปรอินสแตนซ์จำนวนมากและไม่ต้องเปลี่ยนพารามิเตอร์ของนิพจน์แลมบ์ดาของคุณ

สำหรับผู้ที่สนใจฉันได้เขียนบันทึกเกี่ยวกับวิธีการใช้ java.util.function library: http://sysdotoutdotprint.com/index.php/2017/04/28/java-util-function-library/


1

คุณสามารถใช้ไลบรารี jOOL - https://github.com/jOOQ/jOOL

มันได้เตรียมอินเทอร์เฟซของฟังก์ชั่นที่มีจำนวนพารามิเตอร์ที่แตกต่างกัน ตัวอย่างเช่นคุณสามารถใช้org.jooq.lambda.function.Function3ฯลฯ จากถึงFunction0Function16

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