मैं जावा में एक अनाम फ़ंक्शन कैसे लिख सकता हूं?


87

क्या यह भी संभव है?


6
ध्यान दें कि यह अब जावा 8 में संभव है - नीचे मार्क रोटेटेवेल द्वारा लैम्ब्डा एक्सप्रेशंस के बारे में उत्तर देखें।
जोसिया योडर

जवाबों:


81

यदि आप एक अनाम फ़ंक्शन का मतलब है, और जावा 8 से पहले जावा के एक संस्करण का उपयोग कर रहे हैं, तो एक शब्द में, नहीं। ( यदि आप जावा 8+ का उपयोग करते हैं तो लैम्ब्डा अभिव्यक्तियों के बारे में पढ़ें )

हालाँकि, आप किसी फ़ंक्शन को इंटरफ़ेस को लागू कर सकते हैं जैसे:

Comparator<String> c = new Comparator<String>() {
    int compare(String s, String s2) { ... }
};

और आप लगभग अनाम फ़ंक्शन प्राप्त करने के लिए आंतरिक कक्षाओं के साथ इसका उपयोग कर सकते हैं :)


6
अभी नहीं। जावा 7 में यह संभव होने जा रहा है: stackoverflow.com/questions/233579/closures-in-java-7
इल्या बॉयंडिन

2
इस बीच, JDK7 की प्रतीक्षा करते समय, अनाम तरीकों को एक OO संदर्भ में en.wikipedia.org/wiki/Command_pattern
gpampara

1
closured फ्लॉप जावा 7. में आने से पहले
Thorbjorn Ravn एंडरसन

5
मुझे लगता है कि आपको अपना उत्तर संशोधित करना चाहिए क्योंकि हमारे पास अनाम फ़ंक्शन जावा 8 के साथ है।
Node.JS

45

यहाँ एक अनाम आंतरिक वर्ग का उदाहरण दिया गया है।

System.out.println(new Object() {
    @Override public String toString() {
        return "Hello world!";
    }
}); // prints "Hello world!"

यह बहुत उपयोगी नहीं है जैसा कि यह है, लेकिन यह दिखाता है कि एक अनाम आंतरिक वर्ग की आवृत्ति extends Objectऔर @Overrideउसकी toString()विधि कैसे बनाई जाए ।

यह सभी देखें


अनाम आंतरिक कक्षाएं बहुत उपयोगी होती हैं जब आपको लागू करने की आवश्यकता होती है interfaceजो अत्यधिक पुन: प्रयोज्य नहीं हो सकती है (और इसलिए अपने स्वयं के नामित वर्ग के लिए रिफैक्टिंग के लायक नहीं है)। एक शिक्षाप्रद उदाहरण java.util.Comparator<T>छँटाई के लिए एक प्रथा का उपयोग कर रहा है ।

यहां एक उदाहरण दिया गया है कि आप किस तरह से एक String[]आधार बना सकते हैं String.length()

import java.util.*;
//...

String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
    @Override public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }           
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"

तुलना-द्वारा-घटाव चाल का उपयोग यहां नोट करें। यह कहा जाना चाहिए कि यह तकनीक सामान्य रूप से टूटी हुई है: यह केवल तब लागू होती है जब आप गारंटी दे सकते हैं कि यह अतिप्रवाह नहीं होगा ( Stringलंबाई के साथ ऐसा ही है )।

यह सभी देखें


5
EventListenerऔसत स्विंग एप्लिकेशन में अधिकांश अन्य घटनाओं को (उप) कार्यान्वयन के रूप में पाया जा सकता है ।
बालुसक

@ बालसुख: प्रश्न का लिंक जोड़ा गया "वे कैसे उपयोग किए जाते हैं"
पॉलीजेनक्लूबिकेंट

@ बाल्सक: स्टैकओवरफ्लो ने हाल ही में Linkedसाइडबार को जोड़ा है , इसलिए मैं इसका उपयोग करने की पूरी कोशिश कर रहा हूं।
पॉलीजेन लुब्रीकेंट

12

जावा 8 में लैम्ब्डा एक्सप्रेशन की शुरुआत के साथ अब आप गुमनाम तरीके अपना सकते हैं।

कहो कि मेरे पास एक वर्ग है Alphaऔर मैं Alphaएक विशिष्ट स्थिति पर फ़िल्टर करना चाहता हूं । ऐसा करने के लिए आप एक का उपयोग कर सकते हैं Predicate<Alpha>। यह एक कार्यात्मक इंटरफ़ेस है जिसमें एक विधि testहै जो एक को स्वीकार करता है Alphaऔर एक रिटर्न देता है boolean

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

List<Alpha> filter(Predicate<Alpha> filterPredicate)

पुराने अनाम वर्ग समाधान के साथ आपको कुछ इस तरह की आवश्यकता होगी:

filter(new Predicate<Alpha>() {
   boolean test(Alpha alpha) {
      return alpha.centauri > 1;
   }
});

जावा 8 लैम्ब्डा के साथ आप यह कर सकते हैं:

filter(alpha -> alpha.centauri > 1);

अधिक विस्तृत जानकारी के लिए लैम्बडा एक्सप्रेशंस ट्यूटोरियल देखें


2
विधि संदर्भ भी उपयोगी हैं। उदाहरण के लिए क्रमबद्ध करें (स्ट्रिंग :: ComparToIgnoreCase
जोशिया योडर

9

एक मौजूदा प्रकार के इंटरफ़ेस को लागू करने या विस्तारित करने वाले अनाम आंतरिक वर्गों को अन्य उत्तरों में किया गया है, हालांकि यह ध्यान देने योग्य है कि कई तरीकों को लागू किया जा सकता है (उदाहरण के लिए अक्सर जावा-शैली की घटनाओं के साथ)।

थोड़ी मान्यता प्राप्त विशेषता यह है कि यद्यपि अनाम आंतरिक वर्गों का कोई नाम नहीं है, उनके पास एक प्रकार है। इंटरफ़ेस में नए तरीके जोड़े जा सकते हैं। इन विधियों को केवल सीमित मामलों में ही लागू किया जा सकता है। मुख्य रूप से सीधे newअभिव्यक्ति पर ही और कक्षा के भीतर (उदाहरण के शुरुआती सहित)। यह शुरुआती लोगों को भ्रमित कर सकता है, लेकिन यह पुनरावृत्ति के लिए "दिलचस्प" हो सकता है।

private static String pretty(Node node) {
    return "Node: " + new Object() {
        String print(Node cur) {
            return cur.isTerminal() ?
                cur.name() :
                ("("+print(cur.left())+":"+print(cur.right())+")");
        }
    }.print(node);
}

(मैं मूल रूप से इस का उपयोग करते हुए लिखा nodeबजाय curमें printविधि। कैप्चरिंग "परोक्ष करने के लिए कहते हैं कि कोई final" स्थानीय लोगों? )


nodefinalयहां घोषित किया जाना चाहिए ।
बालुसक

@ बालसुके अच्छा कैच। वास्तव में मेरी गलती का उपयोग नहीं करना था cur
टॉम हॉल्टिन -

@Tom: +1 अच्छी तकनीक! क्या वास्तव में इसका प्रयोग कहीं भी किया जाता है? इस विशिष्ट पैटर्न के लिए कोई नाम?
पॉलीजेन लुब्रिकेंट

@ पॉलीऑक्सीजैलेब्रिकेंट्स जहाँ तक मुझे नहीं पता। एक पूरी अतिरिक्त वस्तु की लागत! (और एक वर्ग।) डबल ब्रेस मुहावरे के बारे में बहुत कुछ सच था। सही सोच वाले लोग मुहावरे के आस-पास के मन को भांपते नहीं हैं।
टॉम हॉल्टिन -

@ पोलियारोपेग्युबेलिकेंट वास्तव में मुझे ऐसा नहीं लगता है कि कई (स्व-निहित) पुनरावर्ती एल्गोरिदम हैं। विशेष रूप से जो पूंछ-पुनरावर्ती नहीं हैं (या आसानी से ऐसा बनाया गया है) और सार्वजनिक विधि को कॉल करके लागू नहीं किया जा सकता है ( "Node" +दूसरी विधि को आवश्यक बनाने के लिए थोड़ा अप्रासंगिक नोट करें )। / मेरा कोई नाम नहीं है। शायद मैं एक नामकरण "पोल" (सीडब्ल्यू) प्रश्न बना सकता हूं, और क्या यह गुमनामी में बदल गया है।
टॉम हॉकिन -

1

हां यदि आप नवीनतम जावा का उपयोग कर रहे हैं जो कि संस्करण 8 है। जावा 8 उन अनाम कार्यों को परिभाषित करना संभव बनाता है जो पिछले संस्करणों में असंभव था।

यह जानने के लिए कि हम कैसे गुमनाम कार्यों, कक्षाओं की घोषणा कर सकते हैं, जावा डॉक्स से उदाहरण लेते हैं

निम्नलिखित उदाहरण, HelloWorldAnonymousClasses, स्थानीय चरों के आरंभिक बयानों में गुमनाम कक्षाओं का उपयोग करता है फ्रेंचग्रेस्टिंग और स्पैनिशग्रीटिंग, लेकिन चर के आरंभ के लिए एक स्थानीय वर्ग का उपयोग करता है।

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }            
}

बेनामी वर्गों का सिंटेक्स

FrenchGreeting ऑब्जेक्ट की तात्कालिकता पर विचार करें:

    HelloWorld frenchGreeting = new HelloWorld() {
        String name = "tout le monde";
        public void greet() {
            greetSomeone("tout le monde");
        }
        public void greetSomeone(String someone) {
            name = someone;
            System.out.println("Salut " + name);
        }
    };

अनाम वर्ग की अभिव्यक्ति में निम्नलिखित शामिल हैं:

  • newऑपरेटर
  • लागू करने के लिए एक इंटरफ़ेस का नाम या विस्तार करने के लिए एक वर्ग। इस उदाहरण में, अनाम वर्ग इंटरफ़ेस को लागू कर रहा है HelloWorld।

  • कोष्ठक जिसमें एक रचनाकार के तर्क होते हैं, एक सामान्य श्रेणी के उदाहरण सृजन अभिव्यक्ति की तरह। नोट: जब आप एक इंटरफ़ेस लागू करते हैं, तो कोई निर्माता नहीं होता है, इसलिए आप कोष्ठक की एक खाली जोड़ी का उपयोग करते हैं, जैसा कि इस उदाहरण में है।

  • एक निकाय, जो एक वर्ग घोषणा निकाय है। अधिक विशेष रूप से, शरीर में, विधि घोषणाओं की अनुमति है लेकिन कथन नहीं हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.