Java lambda có thể có nhiều hơn 1 tham số không?


156

Trong Java, có thể có lambda chấp nhận nhiều loại khác nhau không?

Tức là: Biến đơn hoạt động:

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

Varargs cũng hoạt động:

    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 })));

Nhưng tôi muốn một cái gì đó có thể chấp nhận nhiều loại đối số khác nhau, ví dụ:

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

Việc sử dụng chính là để có các chức năng nội tuyến nhỏ bên trong các chức năng cho thuận tiện.

Tôi đã xem qua google và kiểm tra Gói chức năng của Java, nhưng không thể tìm thấy. Điều này có thể không?

Câu trả lời:


178

Có thể nếu bạn xác định một giao diện chức năng như vậy với nhiều tham số loại. Không có loại được xây dựng như vậy. (Có một vài loại giới hạn với nhiều tham số.)

@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';
}

Tôi đã gọi nó Function6ở đây. Tên này theo ý của bạn, chỉ cần cố gắng không đụng độ với các tên hiện có trong các thư viện Java.


Cũng không có cách nào để xác định một số lượng tham số loại khác nhau, nếu đó là những gì bạn đang hỏi về.


Một số ngôn ngữ, như Scala, xác định một số loại được xây dựng trong các loại như vậy, với các tham số loại 1, 2, 3, 4, 5, 6, v.v.


58
Bạn luôn có thể sử dụng Currying:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger

@SotiriosDelimanolis: Tôi muốn chọn một tên khác Functionmà từ đó đụng độ với java.util.function.Function<T,R>nó có thể không rõ ràng cho người mới bắt đầu.
Nikolas

@Nikolas Điều đó hợp lý. Đã chỉnh sửa.
Sotirios Delimanolis

39

Đối với một cái gì đó với 2 tham số, bạn có thể sử dụng BiFunction. Nếu bạn cần thêm, bạn có thể xác định giao diện chức năng của riêng mình, như vậy:

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

Nếu có nhiều hơn một tham số, bạn cần đặt dấu ngoặc đơn quanh danh sách đối số, như vậy:

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

34

Trong trường hợp này, bạn có thể sử dụng các giao diện từ thư viện mặc định (java 1.8):

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

Có một ví dụ nhỏ (không phải tốt nhất) về phương thức mặc định trong giao diện:

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
Bạn sẽ nhận được nhiều phiếu bầu hơn từ người hâm mộ Java8 nếu bạn sửa đổi câu hỏi của mình để minh họa cách các giao diện đó có thể được sử dụng để đáp ứng yêu cầu.
Martin Cowie

3
BiFunction cho phép bạn chỉ xác định các hàm hai đối số, câu hỏi là về các hàm với bất kỳ số lượng đối số nào
Dmitry Klochkov

8

Để sử dụng lambda: Có ba loại hoạt động:
1. Chấp nhận tham số -> Người tiêu dùng
2. Kiểm tra tham số trả về boolean -> Dự đoán
3. Thao tác tham số và giá trị trả về -> Chức năng

Giao diện chức năng Java tối đa hai tham số:
Giao diện tham số đơn Chức năng dự đoán
người tiêu dùng Hai giao diện tham số BiConsumer BiPredicate BiFunction







Đối với nhiều hơn hai , bạn phải tạo giao diện chức năng như sau (Loại người tiêu dùng):

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

1

Một cách khác, không chắc chắn nếu điều này áp dụng cho vấn đề cụ thể của bạn nhưng đối với một số vấn đề có thể áp dụng là sử dụng UnaryOperatortrong thư viện java.util.feft. nơi nó trả về cùng loại bạn chỉ định, vì vậy bạn đặt tất cả các biến của mình vào một lớp và nó có phải là tham số không:

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;
    }
}

Vì vậy, lớp bạn có, trong trường hợp này Person, có thể có nhiều biến thể hiện và sẽ không phải thay đổi tham số của biểu thức lambda của bạn.

Đối với những người quan tâm, tôi đã viết ghi chú về cách sử dụng thư viện java.util.feft: http://sysdotoutdotprint.com/index.php/2017/04/28/java-util-feft-l Library /


1

Bạn cũng có thể sử dụng thư viện jOOL - https://github.com/jOOQ/jOOL

Nó đã chuẩn bị các giao diện chức năng với số lượng tham số khác nhau. Ví dụ, bạn có thể sử dụng org.jooq.lambda.function.Function3, vv từ Function0lên đến Function16.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.