जावा 8 लंबोदर शून्य तर्क


188

मान लें कि मेरे पास जावा 8 में निम्नलिखित कार्यात्मक इंटरफ़ेस है:

interface Action<T, U> {
   U execute(T t);
}

और कुछ मामलों के लिए मुझे तर्क या वापसी प्रकार के बिना कार्रवाई की आवश्यकता है। तो मैं कुछ इस तरह से लिखता हूं:

Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };

हालाँकि, यह मुझे संकलित त्रुटि देता है, मुझे इसे लिखने की आवश्यकता है

Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};

जो कुरूप है। क्या Voidटाइप पैरामीटर से छुटकारा पाने का कोई तरीका है ?


1
एक पर नजर डालें stackoverflow.com/questions/14319787/...
BobTheBuilder

7
यदि आपको एक कार्रवाई की आवश्यकता है, जैसा कि आपने इसे परिभाषित किया है, तो यह संभव नहीं है। हालाँकि, आपका पहला उदाहरण फिट हो सकता है Runnable, जिसे आप ढूंढ रहे हैंRunnable r = () -> System.out.println("Do nothing!");
एलेक्सिस सी।

1
@BusTheBuilder मैं उस पोस्ट में सुझाव के रूप में एक उपभोक्ता का उपयोग नहीं करना चाहता।
विकू

2
मैट का जवाब प्रकारों को काम करता है, लेकिन जब यह अशक्त रिटर्न वैल्यू प्राप्त करता है तो कॉलर क्या करता है?
स्टुअर्ट मार्क्स 15

8
आप उंगलियों को पार कर सकते हैं और उम्मीद कर सकते हैं कि इस पोस्ट में 2 और 3 सुझाव जावा 9 के लिए स्वीकार किए जाते हैं!
assylias

जवाबों:


110

एक छोटे हेल्पर फ़ंक्शन के साथ संभव होने वाला सिंटैक्स आपके लिए एक Runnableमें कनवर्ट करता है Action<Void, Void>(आप इसे Actionउदाहरण के लिए रख सकते हैं ):

public static Action<Void, Void> action(Runnable runnable) {
    return (v) -> {
        runnable.run();
        return null;
    };
}

// Somewhere else in your code
 Action<Void, Void> action = action(() -> System.out.println("foo"));

4
यह आपको मिलने वाला सबसे साफ सुथरा वर्क है, IMO, इसलिए +1 (या इंटरफ़ेस में एक स्थिर विधि के साथ)
एलेक्सिस सी।

कॉन्स्टेंटिन योकोव का समाधान नीचे (@FunctionalInterface के साथ) एक बेहतर समाधान है, क्योंकि इसमें जेनरिक शामिल नहीं है और अतिरिक्त कोड की आवश्यकता नहीं है।
उत्तमास

@uthomas क्षमा करें, मुझे कोई उत्तर नहीं मिला है @FunctionalInterface। वह केवल यह कहता है, कि इसका विस्तार संभव नहीं है ...
मैट

1
हाय @ मट, सॉरी। मैंने भी तेजी से प्रतिक्रिया दी। दिए गए प्रश्न के लिए आप उत्तर पूरी तरह से मान्य हैं। दुर्भाग्य से, मेरा वोट बंद है, इसलिए मैं इस उत्तर पर अपना -1 नहीं हटा सकता। दो नोट: 1. Runnableकार्रवाई के बजाय एक कस्टम @FunctionalInterfaceचीज़ लेनी चाहिए जिसे कहा जाता है SideEffect, 2. इस तरह के हेल्पर फ़ंक्शन पर प्रकाश डाला गया है कि कुछ अजीब चल रहा है और शायद अमूर्त टूट गया है।
उत्तमास ११'१६ को

530

उपयोग Supplier अगर यह कुछ भी नहीं लेता है, लेकिन कुछ देता है।

उपयोग Consumer अगर यह कुछ लेता है, लेकिन कुछ भी नहीं लौटाता है।

उपयोग करें Callableयदि यह एक परिणाम देता है और फेंक सकता है (अधिकांश के समान है)Thunk सामान्य सीएस संदर्भ में)।

Runnableयदि यह न तो उपयोग करता है और न ही फेंक सकता है।


एक उदाहरण के रूप में मैंने "शून्य" रिटर्न कॉल को लपेटने के लिए ऐसा किया public static void wrapCall(Runnable r) { r.run(); }:। धन्यवाद
मैक्सेसंस

13
सुंदर जवाब। छोटा और सटीक।
क्लिंट ईस्टवुड

दुर्भाग्य से, अगर यह एक जाँच अपवाद फेंकना चाहिए मदद नहीं करता है।
जेसी ग्लिक

13
इस उत्तर को पूरा करने के लिए, जो संपादित करने लायक नहीं होगा: आप BiConsumer (2, रिटर्न 0), फ़ंक्शन (1, रिटर्न 1) और BiFunction (2, रिटर्न 1 लेता है) का उपयोग कर सकते हैं। उन लोगों को जानना सबसे महत्वपूर्ण है
CLOVIS

2
क्या कॉल करने योग्य कुछ भी है (जो इसके कॉल () विधि में एक अपवाद को फेंक देता है) लेकिन किसी भी वापसी मूल्य की आवश्यकता होती है?
dpelisek

40

लंबोदर:

() -> { System.out.println("Do nothing!"); };

वास्तव में एक इंटरफ़ेस के लिए एक कार्यान्वयन का प्रतिनिधित्व करता है जैसे:

public interface Something {
    void action();
}

जो आपके द्वारा परिभाषित एक से पूरी तरह से अलग है। इसलिए आपको त्रुटि मिलती है।

चूँकि आप अपना विस्तार नहीं कर सकते @FunctionalInterface, और न ही किसी नए को पेश कर सकते हैं , तो मुझे लगता है कि आपके पास ज्यादा विकल्प नहीं हैं। आप यह Optional<T>बताने के लिए इंटरफेस का उपयोग कर सकते हैं कि कुछ मान (वापसी प्रकार या विधि पैरामीटर) गायब है, हालांकि। हालाँकि, यह लैम्ब्डा बॉडी को सरल नहीं बनाएगा।


समस्या यह है कि आपका Somethingफ़ंक्शन मेरे Actionप्रकार का उपप्रकार नहीं हो सकता है , और मेरे पास दो भिन्न प्रकार नहीं हो सकते हैं।
विकू

तकनीकी रूप से वह कर सकता है, लेकिन उसने कहा कि वह इससे बचना चाहता है। :)
कोन्स्टेंटिन योवकोव

31

आप उस विशेष मामले के लिए एक उप-इंटरफ़ेस बना सकते हैं:

interface Command extends Action<Void, Void> {
  default Void execute(Void v) {
    execute();
    return null;
  }
  void execute();
}

यह इनहेरिट की गई पैरामीटरलाइज्ड विधि को ओवरराइड करने के लिए एक डिफ़ॉल्ट विधि का उपयोग करता है Void execute(Void), कॉल को सरल विधि में दर्शाता है void execute()

परिणाम यह है कि यह उपयोग करने के लिए बहुत सरल है:

Command c = () -> System.out.println("Do nothing!");

यह क्रिया <शून्य, शून्य> कहां से आ रही है? न तो स्विंग और न ही JAX-WX एक्शन इंटरफेस में इतना सामान्य इंटरफ़ेस है?
luis.espinal

1
@ luis.espinal: Action<T, U>प्रश्न में घोषित किया गया है .....
जोर्डो

हाहाहा, मैं कैसे चूक गया? धन्यवाद!
luis.espinal

6

मुझे लगता है कि यह तालिका छोटी और उपयोगी है:

Supplier       ()    -> x
Consumer       x     -> ()
Callable       ()    -> x throws ex
Runnable       ()    -> ()
Function       x     -> y
BiFunction     x,y   -> z
Predicate      x     -> boolean
UnaryOperator  x1    -> x2
BinaryOperator x1,x2 -> x3

जैसा कि अन्य उत्तरों पर कहा गया है, इस समस्या के लिए उपयुक्त विकल्प ए है Runnable


5

यह संभव नहीं है। एक फ़ंक्शन जिसमें एक गैर-शून्य रिटर्न प्रकार होता है (भले ही यह हो Void) को एक मूल्य वापस करना पड़ता है। हालाँकि आप स्थैतिक तरीके जोड़ सकते हैं Actionजो आपको "a" बनाने की अनुमति देता है Action:

interface Action<T, U> {
   U execute(T t);

   public static Action<Void, Void> create(Runnable r) {
       return (t) -> {r.run(); return null;};
   }

   public static <T, U> Action<T, U> create(Action<T, U> action) {
       return action;
   } 
}

यह आपको निम्नलिखित लिखने की अनुमति देगा:

// create action from Runnable
Action.create(()-> System.out.println("Hello World")).execute(null);
// create normal action
System.out.println(Action.create((Integer i) -> "number: " + i).execute(100));

4

अपने कार्यात्मक इंटरफ़ेस के अंदर एक स्थिर विधि जोड़ें

package example;

interface Action<T, U> {
       U execute(T t);
       static  Action<Void,Void> invoke(Runnable runnable){
           return (v) -> {
               runnable.run();
                return null;
            };         
       }
    }

public class Lambda {


    public static void main(String[] args) {

        Action<Void, Void> a = Action.invoke(() -> System.out.println("Do nothing!"));
        Void t = null;
        a.execute(t);
    }

}

उत्पादन

Do nothing!

3

मुझे नहीं लगता कि यह संभव है, क्योंकि फ़ंक्शन परिभाषाएं आपके उदाहरण में मेल नहीं खाती हैं।

आपके लंबोदर अभिव्यक्ति का मूल्यांकन बिल्कुल वैसा ही है

void action() { }

जबकि आपकी घोषणा दिखती है

Void action(Void v) {
    //must return Void type.
}

एक उदाहरण के रूप में, यदि आपके पास निम्नलिखित इंटरफ़ेस है

public interface VoidInterface {
    public Void action(Void v);
}

एक ही प्रकार का फ़ंक्शन (त्वरित करते समय) जो कि कॉम्पैटिबल होगा, जैसा दिखता है

new VoidInterface() {
    public Void action(Void v) {
        //do something
        return v;
    }
}

और या तो रिटर्न स्टेटमेंट या तर्क का अभाव आपको एक कंपाइलर त्रुटि देगा।

इसलिए, यदि आप एक फ़ंक्शन की घोषणा करते हैं जो एक तर्क लेता है और एक रिटर्न देता है, तो मुझे लगता है कि इसे फ़ंक्शन में बदलना असंभव है जो न तो ऊपर उल्लिखित है।


3

केवल संदर्भ के लिए जो कार्यात्मक इंटरफ़ेस का उपयोग विधि संदर्भ के लिए किया जा सकता है, विधि थ्रो और / या मान लौटाता है।

void notReturnsNotThrows() {};
void notReturnsThrows() throws Exception {}
String returnsNotThrows() { return ""; }
String returnsThrows() throws Exception { return ""; }

{
    Runnable r1 = this::notReturnsNotThrows; //ok
    Runnable r2 = this::notReturnsThrows; //error
    Runnable r3 = this::returnsNotThrows; //ok
    Runnable r4 = this::returnsThrows; //error

    Callable c1 = this::notReturnsNotThrows; //error
    Callable c2 = this::notReturnsThrows; //error
    Callable c3 = this::returnsNotThrows; //ok
    Callable c4 = this::returnsThrows; //ok

}


interface VoidCallableExtendsCallable extends Callable<Void> {
    @Override
    Void call() throws Exception;
}

interface VoidCallable {
    void call() throws Exception;
}

{
    VoidCallableExtendsCallable vcec1 = this::notReturnsNotThrows; //error
    VoidCallableExtendsCallable vcec2 = this::notReturnsThrows; //error
    VoidCallableExtendsCallable vcec3 = this::returnsNotThrows; //error
    VoidCallableExtendsCallable vcec4 = this::returnsThrows; //error

    VoidCallable vc1 = this::notReturnsNotThrows; //ok
    VoidCallable vc2 = this::notReturnsThrows; //ok
    VoidCallable vc3 = this::returnsNotThrows; //ok
    VoidCallable vc4 = this::returnsThrows; //ok
}

कृपया कुछ और संदर्भ जोड़ें। यह दिलचस्प लग रहा है, लेकिन इसका अर्थ तुरंत स्पष्ट नहीं है।
bnieland
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.