Theo như tôi biết, chỉ có hai loại chức năng, phá hủy và xây dựng.
Trong khi chức năng xây dựng, như tên của nó, tạo ra một cái gì đó, một chức năng phá hủy phá hủy một cái gì đó, nhưng không phải theo cách bạn có thể nghĩ bây giờ.
Ví dụ, hàm
Function<Integer,Integer> f = (x,y) -> x + y
là một trong những xây dựng . Khi bạn cần xây dựng một cái gì đó. Trong ví dụ, bạn đã xây dựng bộ tuple (x, y) . Các hàm cấu tạo có vấn đề là không thể xử lý các đối số vô hạn. Nhưng điều tồi tệ nhất là, bạn không thể cứ để ngỏ một cuộc tranh cãi. Bạn không thể chỉ nói "well, let x: = 1" và thử mọi y bạn có thể muốn thử. Bạn phải xây dựng mỗi khi toàn bộ tuple với
x := 1
. Vì vậy, nếu bạn muốn xem những gì các hàm trả về cho y := 1, y := 2, y := 3
bạn, bạn phải viết f(1,1) , f(1,2) , f(1,3)
.
Trong Java 8, các hàm xây dựng nên được xử lý (hầu hết thời gian) bằng cách sử dụng tham chiếu phương thức vì không có nhiều lợi ích khi sử dụng hàm lambda có tính xây dựng. Chúng hơi giống các phương thức tĩnh. Bạn có thể sử dụng chúng, nhưng chúng không có trạng thái thực.
Loại còn lại là loại phá hoại, nó lấy một thứ gì đó và tháo dỡ nó nếu cần. Ví dụ, hàm hủy diệt
Function<Integer, Function<Integer, Integer>> g = x -> (y -> x + y)
làm tương tự như chức năng f
được xây dựng. Lợi ích của một hàm hủy là bạn có thể xử lý các đối số vô hạn ngay bây giờ, điều này đặc biệt thuận tiện cho các luồng và bạn chỉ có thể để mở các đối số. Vì vậy, nếu bạn lại muốn xem kết quả sẽ như thế nào nếu x := 1
và y := 1 , y := 2 , y := 3
, bạn có thể nói h = g(1)
và
h(1)
là kết quả cho y := 1
, h(2)
cho y := 2
và h(3)
cho y := 3
.
Vì vậy, ở đây bạn có một trạng thái cố định! Điều đó khá năng động và đó là hầu hết thời gian những gì chúng tôi muốn từ một lambda.
Các mẫu như Factory sẽ dễ dàng hơn rất nhiều nếu bạn có thể chỉ cần đưa vào một chức năng làm việc cho bạn.
Những cái phá hủy dễ dàng kết hợp với nhau. Nếu loại phù hợp, bạn có thể chỉ cần soạn chúng theo ý muốn. Bằng cách sử dụng đó, bạn có thể dễ dàng xác định các hình thái giúp việc thử nghiệm (với các giá trị không thay đổi) dễ dàng hơn rất nhiều!
Bạn cũng có thể làm điều đó với một cấu trúc, nhưng bố cục phá hủy trông đẹp hơn và giống như một danh sách hoặc một trình trang trí, và một cấu trúc trông rất giống một cái cây. Và những thứ như backtracking với các chức năng xây dựng chỉ là không tốt. Bạn chỉ có thể lưu các hàm từng phần của hàm hủy (lập trình động) và trên "backtrack" chỉ cần sử dụng hàm hủy cũ. Điều đó làm cho mã nhỏ hơn rất nhiều và dễ đọc hơn. Với các hàm xây dựng, bạn ít nhiều phải nhớ tất cả các đối số, có thể là rất nhiều.
Vì vậy, tại sao cần BiFunction
phải có nhiều câu hỏi hơn là tại sao không có TriFunction
?
Trước hết, rất nhiều thời gian bạn chỉ có một vài giá trị (nhỏ hơn 3) và chỉ cần một kết quả, vì vậy một hàm hủy thông thường sẽ không cần thiết, một hàm xây dựng sẽ tốt. Và có những thứ như monads thực sự cần một chức năng xây dựng. Nhưng ngoài điều đó ra, thực sự không có nhiều lý do chính đáng tại sao lại có BiFunction
. Điều đó không có nghĩa là nó nên bị loại bỏ! Tôi chiến đấu cho Môn phái của mình cho đến khi chết!
Vì vậy, nếu bạn có nhiều đối số, mà bạn không thể kết hợp thành một lớp vùng chứa logic và nếu bạn cần hàm có tính xây dựng, hãy sử dụng tham chiếu phương thức. Nếu không, hãy thử sử dụng khả năng mới có được của các hàm phá hủy, bạn có thể thấy mình đang làm rất nhiều việc với ít dòng mã hơn rất nhiều.