Biểu thức Lambda so với tham chiếu phương thức [đã đóng]


114

IntelliJ tiếp tục đề xuất tôi thay thế các biểu thức lambda của tôi bằng các tham chiếu phương thức.

Có sự khác biệt khách quan nào giữa cả hai không?


4
Không hẳn, tôi không nhìn thấy vật nào cả! Nó trông giống như một cuộc gọi tĩnh với tôi
Gerard

9
Tất nhiên! Nhưng "bạn cũng không tìm thấy" ... Đó là vấn đề của thị hiếu, tôi đã lo lắng hơn về các khía cạnh kỹ thuật hơn. Trong thực tế, như bạn đã nói rằng chúng giống nhau, đó là một câu trả lời tốt cho tôi. Dù sao, như IntelliJ đề xuất nó, tôi đoán rằng nhìn chung được đánh giá cao hơn khi xem tham chiếu phương thức hơn là lambda (tuy nhiên, không phải đối với tôi).
Gerard

15
Mã của một biểu thức lambda được biên dịch thành một phương thức tổng hợp trong khi các tham chiếu phương thức hoạt động mà không có (ngoại lệ: các cấu trúc đặc biệt như Type[]::new). Lớp ẩn danh được tạo trong thời gian chạy sẽ giống nhau. JRE không tạo ra bất kỳ sự khác biệt nào giữa chúng. Vì vậy, sử dụng một tài liệu tham khảo phương pháp sẽ giúp bạn tiết kiệm một phương pháp trong mã biên dịch của bạn, mặt khác, bạn có thể không dừng lại ở đó khi thực hiện từng bước gỡ lỗi ...
Holger

6
Bây giờ câu hỏi sẽ được kết thúc ... Thật tệ cho tất cả những người dùng như tôi không biết sự khác biệt giữa lambdas và tài liệu tham khảo, ngay cả khi không có bất kỳ điều gì quyết định. Tôi cũng thắc mắc tại sao không ai dám trả lời như vậy? Đó là câu trả lời phù hợp với tôi.
Gerard

3
Trả lời một câu hỏi đóng hai năm tuổi có lẽ là một ý tưởng tồi nhưng đối với những người THỰC SỰ ĐỌC câu hỏi thì đây là hướng dẫn của Oracle ( docs.oracle.com/javase/tutorial/java/javaOO/… ) nói: biểu thức lambda nhỏ gọn, dễ đọc cho các phương thức đã có tên.
ngày mai

Câu trả lời:


187

Hãy để tôi cung cấp một số quan điểm về lý do tại sao chúng tôi thêm tính năng này vào ngôn ngữ, trong khi rõ ràng chúng tôi không cần phải làm như vậy (tất cả các tham chiếu phương thức có thể được biểu thị dưới dạng lambdas.)

Lưu ý rằng không có câu trả lời đúng . Bất kỳ ai nói "luôn sử dụng phương thức ref thay vì lambda" hoặc "luôn sử dụng lambda thay vì phương thức ref" đều nên bị bỏ qua.

Câu hỏi này rất giống với tinh thần "khi nào tôi nên sử dụng một lớp có tên so với một lớp ẩn danh"? Và câu trả lời là như nhau: khi bạn thấy nó dễ đọc hơn . Chắc chắn có những trường hợp chắc chắn là một hoặc chắc chắn là khác nhưng có một loạt các màu xám ở giữa và phải sử dụng phán đoán.

Lý thuyết đằng sau phương pháp refs rất đơn giản: tên là vấn đề . Nếu một phương thức có tên, thì việc đề cập đến nó bằng tên, thay vì một túi mã bắt buộc mà cuối cùng chỉ quay lại và gọi nó, thường (nhưng không phải lúc nào!) Rõ ràng và dễ đọc hơn.

Các tranh luận về hiệu suất hoặc về việc đếm các ký tự chủ yếu là các vòng màu đỏ, và bạn nên bỏ qua chúng. Mục tiêu là viết mã rõ ràng những gì nó làm. Phương pháp refs rất thường xuyên (nhưng không phải lúc nào cũng vậy!) Giành chiến thắng trên số liệu này, vì vậy chúng tôi đã bao gồm chúng như một tùy chọn, được sử dụng trong những trường hợp đó.

Một điều quan trọng cần cân nhắc về việc liệu các ref của phương thức có làm rõ hoặc làm xáo trộn ý định là liệu nó có rõ ràng từ ngữ cảnh hình dạng của hàm đang được biểu diễn hay không. Trong một số trường hợp (ví dụ: map(Person::getLastName)khá rõ ràng từ ngữ cảnh mà một hàm ánh xạ thứ này sang thứ khác được yêu cầu và trong những trường hợp như thế này, tham chiếu phương thức tỏa sáng. Trong những trường hợp khác, việc sử dụng phương thức ref yêu cầu người đọc tự hỏi về loại của hàm đang được mô tả; đây là một dấu hiệu cảnh báo rằng lambda có thể dễ đọc hơn, ngay cả khi nó dài hơn.

Cuối cùng, những gì chúng tôi nhận thấy là hầu hết mọi người lúc đầu tránh xa các tham chiếu phương thức bởi vì họ cảm thấy thậm chí còn mới hơn và kỳ lạ hơn lambdas, và do đó, ban đầu thấy chúng "ít đọc hơn", nhưng theo thời gian, khi họ quen với cú pháp, thường thay đổi hành vi của họ và thu hút các tham chiếu phương pháp khi họ có thể. Vì vậy, hãy lưu ý rằng phản ứng chủ quan "ít đọc" ban đầu của bạn gần như chắc chắn dẫn đến một số khía cạnh của thành kiến ​​gia đình, và bạn nên cho mình cơ hội để làm quen với cả hai trước khi đưa ra ý kiến ​​theo kiểu.


25
@Gerard Cảm ơn bạn sẽ là một câu trả lời tốt hơn.
Yassin Hajaj

3
@Gerard Có vẻ như Brian đang nói "Không, không có"
dj18

Brian, tôi nhận được các kết quả khác nhau bằng cách sử dụng tham chiếu phương thức và lambda cho cùng một phương pháp. Chúng có nên thay thế cho nhau không?
mFeinstein

@mFeinstein Đối với mỗi ref phương thức, có một lambda tương đương (bạn có thể sử dụng hoặc không). Đăng mã dưới dạng một câu hỏi?
Brian Goetz

Tôi muốn, nhưng tôi sợ mã có thể quá lớn, vì đó là Android LiveData, bên trong a Fragment, mà tôi đã chuyển đổi thành một mã Eventđược kích hoạt bởi ViewModel... và hành vi khác sẽ xảy ra khi Android trở lại như cũ Fragment.. .so tôi gặp một thời gian khó khăn đơn giản hóa nó cho một câu hỏi
mFeinstein

10

Các biểu thức lambda dài bao gồm một số câu lệnh có thể làm giảm khả năng đọc mã của bạn. Trong trường hợp như vậy, trích xuất các câu lệnh đó trong một phương thức và tham chiếu nó có thể là một lựa chọn tốt hơn.

Lý do khác có thể là khả năng sử dụng lại . Thay vì sao chép và dán biểu thức lambda của một vài câu lệnh, bạn có thể xây dựng một phương thức và gọi nó từ các vị trí khác nhau trong mã của bạn.


3
So sánh: houses.map(House::getName)houses.map(h -> h.getName()). Lambda có ít hơn hai ký tự. Đúng là kiểu không rõ ràng, nhưng bất kỳ IDE nào cũng sẽ cho bạn biết và ngoài ra, nên sử dụng lambdas khi kiểu là rõ ràng. Tôi có thể đồng ý với bạn về khả năng tái sử dụng, nhưng lambdas chính xác là rất nhỏ nên chúng có thể được xâu chuỗi thay vì tạo ra các phương thức cụ thể lớn. Theo nghĩa đó, các phương pháp nhỏ có thể tái sử dụng nhiều hơn so với một số phương pháp lớn và phức tạp, và do tính rõ ràng của lambdas (và ở một mức độ nhất định, độ dài) nên chúng vẫn dễ đọc.
Gerard

11
Tôi đi cùng Gerald. Khả năng đọc thực sự bị ảnh hưởng khi bạn di chuyển mã, vì vậy bạn phải chuyển đến nó để tiếp tục đọc, sau đó quay lại. Bạn muốn có tất cả các mã liên quan ở cùng một nơi. Ngoài ra, Houselà một ví dụ rất lành tính; thì sao ThreeStoryRedBrickHouseWithBlueDoors. Tôi thích tham chiếu phương thức hơn cho lambda nhiều đối số và đôi khi để nhấn mạnh rằng lambda chỉ về một lệnh gọi phương thức duy nhất. Có ít đi sai với một tài liệu tham khảo phương pháp: bạn có thể đánh sai đối số tại khu vực sử dụng, vô tình đề cập đến một biến từ phạm vi bên ngoài, vv
Marko Topolnik

@Gerard Tôi không đồng ý với tuyên bố đầu tiên của bạn. Nếu bạn sử dụng tốt các tên phương pháp mô tả và nếu bạn trích xuất hàng đống mã lớn, mã chuyển động sẽ cải thiện khả năng đọc. Nếu bạn sử dụng tên phương pháp xáo trộn, tôi đồng ý với bạn.
Torsten
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.