Bagaimana saya bisa menulis fungsi anonim di Java?

89

Apakah itu mungkin?

aarona
sumber
6
Perhatikan bahwa ini sekarang dimungkinkan di Java 8 - lihat jawaban tentang Ekspresi Lambda oleh Mark Rotteveel di bawah ini.
Josiah Yoder

Jawaban:

81

jika yang Anda maksud adalah fungsi anonim, dan menggunakan versi Java sebelum Java 8, maka dengan kata lain, tidak. ( Baca tentang ekspresi lambda jika Anda menggunakan Java 8+ )

Namun, Anda dapat mengimplementasikan antarmuka dengan fungsi seperti ini:

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

dan Anda dapat menggunakan ini dengan kelas dalam untuk mendapatkan fungsi yang hampir anonim :)

chris
sumber
6
Belum. Di Java 7 ini akan menjadi mungkin: stackoverflow.com/questions/233579/closures-in-java-7
Ilya Boyandin
2
Sementara itu, sambil menunggu JDK7, metode anonim dapat diemulasikan dalam konteks OO menggunakan en.wikipedia.org/wiki/Command_pattern
gpampara
1
ditutup tidak berhasil masuk ke Jawa 7.
Thorbjørn Ravn Andersen
5
Saya pikir Anda harus mengubah jawaban Anda karena kami memiliki fungsi anonim dengan Java 8.
Node.JS
45

Berikut adalah contoh kelas dalam anonim.

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

Hal ini tidak sangat berguna seperti itu, tapi itu menunjukkan bagaimana untuk membuat sebuah instance dari kelas batin anonim yang extends Objectdan @Overridenya toString()metode.

Lihat juga


Kelas dalam anonim sangat berguna ketika Anda perlu mengimplementasikan interfaceyang mungkin tidak terlalu dapat digunakan kembali (dan karena itu tidak layak untuk melakukan refactoring ke kelas bernama sendiri). Contoh instruktif adalah menggunakan kebiasaan java.util.Comparator<T>untuk menyortir.

Berikut adalah contoh bagaimana Anda dapat mengurutkan String[]berdasarkan 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]"

Perhatikan trik perbandingan-pengurangan yang digunakan di sini. Harus dikatakan bahwa teknik ini rusak secara umum: ini hanya berlaku jika Anda dapat menjamin bahwa teknik ini tidak akan meluap (seperti halnya dengan Stringpanjang).

Lihat juga

poligenelubricants
sumber
5
Mayoritas kejadian lain dapat ditemukan sebagai EventListener(sub) implementasi dalam aplikasi Swing rata-rata.
BalusC
@BalusC: menambahkan tautan ke pertanyaan "bagaimana penggunaannya"
poligenelubrik
@BalusC: stackoverflow baru-baru ini menambahkan Linkedsidebar, jadi saya melakukan yang terbaik untuk memanfaatkannya.
poligenelubricants
12

Dengan pengenalan ekspresi lambda di Java 8 Anda sekarang dapat memiliki metode anonim.

Katakanlah saya memiliki kelas Alphadan saya ingin memfilter Alphapada kondisi tertentu. Untuk melakukan ini, Anda dapat menggunakan file Predicate<Alpha>. Ini adalah antarmuka fungsional yang memiliki metode testyang menerima Alphadan mengembalikan a boolean.

Dengan asumsi bahwa metode filter memiliki tanda tangan ini:

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

Dengan solusi kelas anonim lama, Anda memerlukan sesuatu seperti:

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

Dengan lambda Java 8, Anda dapat melakukan:

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

Untuk informasi lebih detail, lihat tutorial Lambda Expressions

Mark Rotteveel
sumber
2
Referensi metode juga berguna. misalnya urutkan (String :: bandingkanToIgnoreCase
Josiah Yoder
9

Kelas dalam anonim yang mengimplementasikan atau memperluas antarmuka dari tipe yang ada telah dilakukan dalam jawaban lain, meskipun perlu dicatat bahwa beberapa metode dapat diimplementasikan (seringkali dengan kejadian bergaya JavaBean, misalnya).

Sedikit fitur yang dikenali adalah bahwa meskipun kelas dalam anonim tidak memiliki nama, mereka memiliki tipe. Metode baru dapat ditambahkan ke antarmuka. Metode ini hanya dapat dijalankan dalam kasus terbatas. Terutama langsung dinew ekspresi itu sendiri dan di dalam kelas (termasuk penginisialisasi instance). Ini mungkin membingungkan pemula, tapi bisa "menarik" untuk rekursi.

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);
}

(Saya awalnya menulis ini menggunakan nodebukan curdengan printmetode. Katakan TIDAK untuk menangkap finalpenduduk lokal yang " secara implisit "? )

Tom Hawtin - tackline
sumber
nodeharus dideklarasikan di finalsini.
BalusC
@Alus_cantik. Sebenarnya kesalahan saya adalah tidak menggunakan cur.
Tom Hawtin - tackline
@Tom: +1 teknik yang bagus! Apakah itu benar-benar digunakan di mana saja dalam praktiknya? Ada nama untuk pola khusus ini?
poligenelubricants
@polygenelubants Tidak sejauh yang saya tahu. Menghabiskan seluruh objek ekstra! (Dan kelas.) Hal yang sama juga berlaku untuk idiom penjepit ganda. Orang yang berpikiran benar tampaknya tidak keberatan dengan idiom Jalankan Di Sekitar.
Tom Hawtin - tackline
@ polygenelubricants Sebenarnya saya tidak melihat banyak algoritma rekursif (mandiri). Khususnya yang tidak rekursif-ekor (atau mudah dibuat) dan tidak dapat diimplementasikan dengan memanggil metode publik (perhatikan yang sedikit tidak relevan "Node" +untuk membuat metode kedua diperlukan). / Saya tidak punya nama. Mungkin saya bisa membuat pertanyaan penamaan "polling" (CW), dan memilihnya agar tidak dilupakan.
Tom Hawtin - tackline
1

Ya, jika Anda menggunakan java terbaru yaitu versi 8. Java8 memungkinkan untuk mendefinisikan fungsi anonim yang tidak mungkin dilakukan di versi sebelumnya.

Mari kita ambil contoh dari dokumen java untuk mengetahui bagaimana kita dapat mendeklarasikan fungsi anonim, kelas

Contoh berikut, HelloWorldAnonymousClasses, menggunakan kelas anonim dalam pernyataan inisialisasi variabel lokal frenchGreeting dan spanishGreeting, tetapi menggunakan kelas lokal untuk inisialisasi variabel englishGreeting:

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();
    }            
}

Sintaks Kelas Anonim

Pertimbangkan instantiasi objek 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);
        }
    };

Ekspresi kelas anonim terdiri dari berikut ini:

  • The newOperator
  • Nama antarmuka yang akan diterapkan atau kelas yang akan diperluas. Dalam contoh ini, kelas anonim mengimplementasikan antarmuka HelloWorld.

  • Tanda kurung yang berisi argumen ke konstruktor, seperti ekspresi pembuatan instance kelas normal. Catatan: Saat Anda mengimplementasikan sebuah antarmuka, tidak ada konstruktor, jadi Anda menggunakan sepasang tanda kurung kosong, seperti dalam contoh ini.

  • Badan, yang merupakan badan deklarasi kelas. Lebih khusus lagi, di bagian body, deklarasi metode diperbolehkan tetapi pernyataan tidak.

mumair
sumber