Tên của một hàm không có đối số và không trả về gì? [đóng cửa]


80

Trong java.util.functiongói Java 8 , chúng tôi có:

  • Hàm : Đưa ra một đối số, tạo ra một kết quả.
  • Người tiêu dùng : Đưa ra một lập luận, không tạo ra gì.
  • Nhà cung cấp : Không có đối số, tạo ra một kết quả.
  • ... : Các trường hợp khác xử lý nguyên thủy, 2 đối số, v.v ...

Nhưng tôi cần xử lý trường hợp " không tranh luận, không tạo ra gì ".

Không có gì cho điều này trong java.util.functionnal.

Vì vậy, câu hỏi là:

Tên của ' một hàm không có đối số và không trả về gì ' là gì?

Trong Java 8, định nghĩa của nó sẽ là:

@FunctionalInterface
public interface InsertANameHere {
    void execute();
}

Executor đã tồn tại và có một mục đích khác: " Một đối tượng thực thi các nhiệm vụ Runnable đã gửi ". Chữ ký không khớp ( execute(Runnable):void) và thậm chí không phải là giao diện chức năng .

Runnable tồn tại, nhưng nó được liên kết chặt chẽ với bối cảnh luồng:

  • Các gói là java.lang, không java.util.function.
  • Javadoc tuyên bố: " Giao diện Runnable nên được thực hiện bởi bất kỳ lớp nào có phiên bản được dự định thực hiện bởi một luồng ".
  • Tên "Runnable" gợi ý một số mã đang chạy bên trong một luồng.

28
"Nhưng không có gì là cho 'Đưa không cãi nhau, tạo ra không có gì'". - Runnable ?
dùng11153

11
Tôi nghĩ rằng javadoc cho Runnableđã lỗi thời tại thời điểm này, bởi vì Runnable cũng được sử dụng bởi các lớp khác ngoài Thread( Executorví dụ).
SpaceTrucker 20/03/2015

13
@superbob Điều đó không có nghĩa là Runnables chỉ có thể .run()bằng Threads. Trên thực tế, chúng rất được sử dụng cho mục đích chính xác được mô tả trong câu hỏi
blgt 20/03/2015

5
@superbob Đó là mục đích ban đầu, nhưng kể từ Java 8, nó được "trang bị thêm" làm giao diện chức năng. Vì vậy, đây là lý do tại sao bạn không tìm thấy gì trong java.util.function gói.
dùng11153

5
Semi-Snark: ImpureFuntion bởi vì nó chắc chắn chỉ dựa vào tác dụng phụ, nếu không thì đó là no-op. ( En.wikipedia.org/wiki/Pure_function#Impure_functions ) Seriosuly thêm: Imperative (làm điều gì đó), trong đó ít nhất sẽ phù hợp với ngữ nghĩa của khoảng trống thực thi ();
Kristian H

Câu trả lời:


71

Sự lựa chọn của Java để làm theo cách đó với một tên riêng cho mọi arity là ngu ngốc. Nó không chính xác đáng để thi đua. Tuy nhiên, nếu bạn phải vì sự nhất quán hoặc nếu bạn đang viết mã thư viện rất chung chung, các đề xuất của Konrad là tốt. Tôi có thể ném Procedurevào vòng.

Sử dụng mô hình chức năng giả không có nghĩa là các nguyên tắc đặt tên thông thường sẽ xuất hiện ngoài cửa sổ. Các giao diện hầu như luôn luôn được đặt tên theo những gì chúng làm , không phải theo một số ý tưởng cú pháp chung chung. Nếu các chức năng được đặt vào một ngăn xếp hoàn tác, chúng nên được đặt tên UndoFunction. Nếu chúng được gọi từ các sự kiện GUI, chúng nên được đặt tên GUIEventHandler. Bạn bè không để bạn bè duy trì các quy ước đặt tên xấu.


Procedurecũng tốt Đối với bối cảnh, tôi đang phát triển một thư viện chung cần xử lý loại "cấu trúc" này.
superbob 20/03/2015

18
Tôi thích Proceduretừ những ngày pascal của tôi. A Procedurecó tác dụng phụ, a Functionkhông. Vì bạn không trả lại giá trị, điều duy nhất nó có thể làm là có tác dụng phụ.
Spencer Rathbun

Tôi có thể có xu hướng sử dụng ProcedureRIR<T1,T2>cho void proc(T1, int, T2), và tương tự cho các loại khác - có thể tạo ra hầu hết chúng theo yêu cầu thay vì cố gắng nhồi nhét trong mọi loại kết hợp có thể.
supercat

1
Thật vậy, lập trình chức năng thực sự thường không khuyến khích đặt tên theo kiểu Hungary. Đây là nhiều hơn tâm lý của mô hình oo hơn là chức năng.
slebetman

3
If the functions are placed into an undo stack, they should be named UndoFunction.Có một sự khác biệt giữa đặt tên hàm và cho nó một kiểu khác. Trong phong cách chức năng bạn sẽ không tạo ra một UndoFunctonloại vì bây giờ bạn không thể vượt qua nó để flip, curry, compose, filter, map,, vv Theo tôi đó là lý do thực sự quyết định của Java để cung cấp cho các chức năng với arities khác nhau tên gọi khác nhau là ngu ngốc. Tất nhiên, nếu bạn sẽ sử dụng các tác dụng phụ, hãy gọi nó là bất cứ điều gì; bạn đã ném bố cục ra khỏi cửa sổ và bạn cũng không thể sử dụng các chức năng.
Doval

33

Trong thế giới java, nó được gọi là Runnable. Trong thế giới C #, nó được gọi là Action.

Nhưng, có một cái tên tốt hơn phù hợp với cái nhìn rộng lớn hơn về mọi thứ.

Cái nhìn lớn hơn về mọi thứ đến sau, khi bạn quyết định rằng bên cạnh giao diện chức năng không tham số của bạn, bạn cũng cần phải có các giao diện chức năng tương tự chấp nhận một, hai hoặc nhiều đối số hoặc trả về một giá trị. Khi điều đó xảy ra, bạn sẽ muốn tên của tất cả các thực thể đó là đẳng cấu và tương ứng với nhau.

Vì vậy, trong Java, tôi có bộ giao diện chức năng riêng mà tôi gọi Procedurelà s, được định nghĩa như sau:

public interface Procedure
{
    void invoke();
}

public interface Procedure1<T1>
{
    void invoke( T1 argument1 );
}

... (Bạn nhận được hình ảnh.)

Và tôi cũng có một bộ giao diện tương tự được gọi là Functions, được định nghĩa theo cách tương tự, với tham số chung đầu tiên là kiểu trả về:

public interface Function<R>
{
    R invoke();
}

public interface Function1<R,T1>
{
    R invoke( T1 argument1 );
}

Vì vậy, quan điểm của tôi ở đây là Proceduremột cái tên rất hay vì nó phù hợp với tầm nhìn rộng lớn hơn về mọi thứ. Nếu sau này bạn quyết định có các giao diện chức năng tương tự với các phương thức chấp nhận đối số hoặc trả về một giá trị, bạn sẽ chạy vào đây.

LƯU Ý: Về cơ bản, tôi đồng ý với khẳng định của Karl Bielefeldt rằng "các nguyên tắc đặt tên thông thường nên [không] ra khỏi cửa sổ" và rằng "Các giao diện hầu như luôn được đặt tên theo những gì chúng làm, không phải theo một ý tưởng cú pháp chung chung nào." Nhưng lưu ý rằng thậm chí anh ấy cho phép "hầu như luôn luôn". Đôi khi cần có các thủ tục và chức năng (về cơ bản là ẩn danh) và đó là những gì OP đang hỏi và đó là những gì tôi đang trả lời.

Sửa đổi 2017-11-10:

Bạn có thể hỏi, tại sao Function1<R,T1>thay vì Function1<T1,R>? Nó có thể đi theo bất kỳ cách nào, nhưng tôi có sở thích về các giá trị trả về ở bên trái vì tôi thích tuân theo quy ước đặt tên 'convert-from' (đích-từ-nguồn) trái ngược với 'convert-to' (nguồn-to quy ước -destination). (Đó thực sự là một tai nạn hơn là một quy ước, thực sự, theo nghĩa là có lẽ, không ai từng nghĩ đến điều đó, bởi vì nếu họ đưa ra bất kỳ suy nghĩ nào thì họ sẽ đến hội nghị 'chuyển đổi từ'. )

Tôi đã đọc về điều này trong Joel Spolksy - Làm cho mã sai Nhìn sai , đó là một bài viết rất dài, tôi khuyên bạn nên đọc toàn bộ, nhưng nếu bạn muốn chuyển thẳng đến vụ án, hãy tìm kiếm 'TypeFromType', nhưng cung cấp cho bạn TL; DR, ý tưởng là myint = intFromStr( mystr )tốt hơn nhiều myint = strToInt( mystr ), vì trong trường hợp đầu tiên, tên của các loại gần với các giá trị được liên kết, do đó bạn có thể dễ dàng thấy rằng 'int' khớp với 'int' và 'str' khớp với 'str'.

Vì vậy, bằng cách mở rộng, tôi có xu hướng sắp xếp mọi thứ theo cách chúng sẽ xuất hiện trong mã.


1
Giải pháp này thực sự tốt, nó dường như thậm chí còn chống đạn hơn cả Nhà cung cấp, Người tiêu dùng, BiFactor của java, bởi vì nó chỉ đưa mọi thứ xuống chỉ còn hai khái niệm. Nó làm tôi nhớ đến câu trả lời của @Karl Bielefeldt về " Sự lựa chọn của Java để làm theo cách đó với một tên riêng cho mỗi arity [điều đó] thật ngu ngốc ". "Nhược điểm" duy nhất là nó không xử lý các kiểu nguyên thủy và các kết hợp của chúng (những thứ thú vị như DoubleToLongFunction, ToLongBiFunction, ...). Nhưng người nguyên thủy là một mối quan tâm khác ...
superbob 20/03/2015

Đúng. Về cơ bản, một khi bạn bắt đầu thay thế thuốc generic bằng nguyên thủy, điều này có nghĩa là bạn thực sự quan tâm đến hiệu suất, vì vậy sẽ ổn nếu bạn đi lệch khỏi quy ước được trình bày ở đây và sử dụng tên tùy chỉnh cao để cải thiện hiệu suất tùy chỉnh cao.
Mike Nakis

1
Nếu tôi có thể chấp nhận câu trả lời thứ 2, tôi sẽ chọn câu trả lời của bạn nhờ vào các đề xuất Thủ tục N , Hàm N. Tôi vẫn nâng cao nó.
superbob

Tại sao không Function1<T1, R>?
ErikE

@ErikE đó là một câu hỏi rất hay và tôi đã sửa đổi bài đăng của mình để trả lời nó.
Mike Nakis

18

Tại sao không Command? Cho rằng nó không có dữ liệu và không trả lại dữ liệu, nhưng giả sử rằng việc gọi nó gây ra một số hiệu ứng (nếu không nó thực sự là vô nghĩa), tôi tưởng tượng đó là điều duy nhất nó có thể làm - bắn một hành động, làm cho điều gì đó xảy ra.

Nói về điều đó, cũng có một Actionđại biểu chung trong .NET. Không giống như Java, Consumernó có thể mất từ ​​0 đến 16 đối số; nói cách khác, phiên bản đơn giản nhất của nó không mất gì - xem MSDN .

Và vì cái tên không ngụ ý có bất cứ điều gì để "tiêu thụ", nó cũng có vẻ như là một lựa chọn tên tốt.


1
Commandtốt. Nó có thể bị nhầm lẫn với mẫu Command nhưng nó có thể là giải pháp.
superbob 20/03/2015

7
Tôi thích Actionnhiều hơn Command. Một lệnh nghe giống như một cái gì đó được nhận và đánh giá, trong khi một hành động được thực thi cho các tác dụng phụ của nó.
Bergi 20/03/2015

7
Umm ... làm thế nào nó không thể là một mẫu lệnh? Bạn đã xây dựng chính xác thực thể Lệnh! Nó thậm chí có execute()phương pháp được đặt tên theo truyền thống .
0_o

1
Không thích đề xuất Hành động, vì đó là giao diện Xoay phổ biến (và tốt). Lệnh là hợp lý.
user949300 20/03/2015

@ user949300 nhưng tùy thuộc vào ngữ cảnh - Java là một thế giới rộng lớn mà bạn thấy, tôi là nhà phát triển Android (hiện tại) và tôi không có các đặc điểm riêng liên quan đến J2EE;) Tôi đồng ý rằng, tất nhiên, quy ước đặt tên được chọn không nên đụng độ với cái mà khung của bạn sử dụng.
Konrad Morawski
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.