ungkapan lambda ialah ciri baharu yang ditambah dalam Java 8. Ia memperkenalkan konsep pengaturcaraan berfungsi dalam Java. Jadi apakah itu pengaturcaraan berfungsi?
Pengaturcaraan fungsian: Pengaturcaraan fungsional ialah abstraksi berorientasikan matematik yang menerangkan pengiraan sebagai penilaian ungkapan.
Apa yang biasa kami panggil pengaturcaraan berorientasikan objek tergolong dalam pengaturcaraan imperatif Perbezaan antara pengaturcaraan berfungsi dan pengaturcaraan imperatif ialah:
. Pengaturcaraan fungsional berkenaan dengan pemetaan data, manakala pengaturcaraan imperatif berkenaan dengan langkah-langkah untuk menyelesaikan masalah.
Hubungan antara jenis hubungan pengaturcaraan berfungsi (struktur algebra), hubungan pengaturcaraan penting dan langkah untuk menyelesaikan masalah.
Intipati pengaturcaraan berfungsi:
Fungsi dalam pengaturcaraan berfungsi tidak merujuk kepada fungsi dalam komputer, tetapi kepada matematik Fungsi dalam ialah pemetaan pembolehubah bebas. Iaitu: nilai fungsi hanya bergantung pada nilai parameter fungsi dan tidak bergantung pada keadaan lain.
Pengaturcaraan fungsional dalam erti kata yang ketat bermaksud pengaturcaraan tanpa menggunakan pembolehubah boleh ubah, tugasan, gelung dan struktur kawalan penting yang lain.
Faedah pengaturcaraan berfungsi:
Faedah pengaturcaraan berfungsi terutamanya disebabkan oleh ketidakbolehubah. Tanpa keadaan boleh ubah, fungsi secara rujukan telus dan Tiada Kesan Sampingan.
Di atas adalah beberapa konsep asas, tetapi kita mungkin kurang pendedahan kepada aspek ini, jadi pada mulanya saya merasakan bahawa pengaturcaraan berfungsi adalah perkara yang jarang berlaku.
Cakap murah, tunjukkan kodnya!
Mari kita mulakan dengan contoh paling mudah, yang mungkin juga paling banyak diperkenalkan. Contoh. Ha ha!
Tambahkan monitor pada butang.
Gunakan kelas dalaman tanpa nama untuk menambah.
submit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE); } });
Kelemahan kaedah ini: banyak kod templat digunakan, dan satu-satunya kod yang benar-benar diperlukan ialah kod dalam badan kaedah. Oleh itu, ungkapan Lambda yang diperkenalkan dalam Java 8 boleh memudahkan kod jenis ini (sudah tentu, terdapat had. Tidak semua kelas dalaman tanpa nama boleh digunakan, yang akan disebut kemudian.).
Gunakan ungkapan Lambda untuk memudahkan kod
submit.addActionListener((e)->{ JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE); });
Ungkapan Lambda ialah kaedah tanpa nama yang menghantar gelagat seperti data.
Penjelasan
Dapat dilihat bahawa ungkapan kod yang dipermudahkan menggunakan ungkapan Lambda menjadi lebih jelas dan tidak perlu menulis kod templat yang menyusahkan.
Pemudahan selanjutnya
Kurung parameter dan kurungan kerinting badan kod juga boleh ditinggalkan (Apabila hanya terdapat satu parameter, kurungan boleh diabaikan, dan apabila terdapat hanya satu baris kod, Kurung kurawal boleh diabaikan).
ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
Ringkasan
Apabila menggunakan ungkapan Lambda dan bukannya kelas dalaman tanpa nama untuk mencipta objek, blok kod ungkapan Lambda akan menggantikan badan kaedah yang melaksanakan kaedah abstrak. Lambda Setara dengan kaedah tanpa nama.
Ungkapan lambda terdiri daripada tiga bahagian:
Senarai parameter formal. Senarai parameter formal membenarkan peninggalan jenis parameter formal. Jika terdapat hanya satu parameter dalam senarai parameter, kurungan dalam senarai parameter boleh ditinggalkan.
Anak panah (->). Sempang Inggeris dan lebih besar daripada tanda.
blok kod. Jika blok kod hanya mempunyai satu ayat, anda boleh meninggalkan pendakap kerinting. Jika terdapat hanya satu pernyataan return
, anda boleh meninggalkan return
dan ungkapan lambda akan mengembalikan nilai pernyataan ini secara automatik.
Nota:
boleh ditinggalkan kerana pengkompil boleh melakukan jenis inferens, contohnya:
List<Dog> dogs1 = new ArrayList<Dog>(); List<Dog> dogs2 = new ArrayList<>();
Menggunakan sintaks berlian di atas, anda boleh meninggalkan apa yang ada di dalam kurungan sudut Ini ialah peranan inferens jenis.
Tetapi inferens jenis tidak mahakuasa, dan tidak semuanya boleh disimpulkan, jadi kadangkala, masih perlu untuk menambah secara eksplisit jenis parameter formal, contohnya:
Jangan bimbang tentangnya lagi Fungsi khusus kod ini.
BinaryOperator b = (x, y)->x*y; //上面这句代码无法通过编译,下面是报错信息:无法将 * 运算符作用于 java.lang.Object 类型。 The operator * is undefined for the argument type(s) java.lang.Object, java.lang.Object
//添加参数类型,正确的代码。 BinaryOperator<Integer> b = (x, y)->x*y;
Jadi, taip inferens tidak maha kuasa Jika pengkompil tidak dapat menyimpulkannya, itu adalah kesilapan kita Jangan terlalu bergantung pada pengkompil. Kadangkala, anda masih perlu menambah jenis parameter secara eksplisit. Sudah tentu, ini memerlukan lebih banyak latihan.
Seperti yang kita ketahui sebelum ini, ungkapan Lambda boleh menggantikan kelas dalaman tanpa nama untuk memudahkan kod dan menyatakan dengan jelas. Jadi apakah prasyarat untuk menggunakan ungkapan Lambda? -- Antara Muka Fungsian
Jenis ungkapan Lambda, juga dikenali sebagai Jenis Sasaran, mestilah Antara Muka Fungsian. Antara muka yang dipanggil berfungsi merujuk kepada: Antara muka yang hanya mengandungi satu kaedah abstrak. (boleh mengandungi berbilang kaedah lalai, kaedah statik, tetapi mesti mempunyai satu kaedah abstrak sahaja).
Nota: Java 8 menyediakan anotasi khas: @FunctionalInterface
. Digunakan untuk menandakan antara muka sebagai antara muka berfungsi, supaya ia akan diperiksa semasa penyusunan Jika antara muka mengandungi beberapa kaedah abstrak, pengkompil akan melaporkan ralat.
上面使用 Lambda 表达式来为按钮添加了监视器,可以看出来,Lambda 表达式 代替了 new ActionListener()
对象。
所以 Lambda 的表达式就是被当成一个对象。
例如:
ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
从上面这个例子中可以看出来,Lambda 表达式实现的是匿名方法–因此它只能实现特定函数式接口中的唯一方法。
所以 Lambda 表达式有下面两种限制:
Lambda 表达式的目标类型必须是明确的函数式接口。 Lambda 表达式只能为函数式接口创建对象。Lambda只能实现一个方法,因此它只能为含有一个抽象方法的接口(函数式接口)创建对象。 介绍几个 Java 中重要的函数接口
从这种表可以看出来,抽象方法的名字反而不是最重要的了,重要的是参数和返回值。 因为在写 Lambda 表达式的时候,也不要使用 抽象方法名了。
上面使用几个简单的例子来说明上面接口的应用:
测试代码
import java.text.ParseException; import java.util.function.BinaryOperator; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Stream; public class Test { public static void main(String[] args) throws ParseException { //Lambda 表达式中的构造器引用,用于简化代码。 Creat<Dog> c = Dog::new; Dog dog = c.creat("小黑", 15); System.out.println(dog.toString()); Predicate<String> predicate = (words)->{ return words.length() > 20; }; assert predicate.test("I love you yesterday and today!") : "长度小于20"; assert !predicate.test("God bless you!") : "长度小于20"; System.out.println("------------------------"); Consumer<Dog> consumer = System.out::println; consumer.accept(dog); System.out.println("------------------------"); Function<Dog, String> function = (dogObj)->{ return dogObj.getName(); }; System.out.println(function.apply(dog)); System.out.println("------------------------"); Supplier<Dog> supplier = ()->{ return new Dog("大黄", 4); }; System.out.println(supplier.get()); //一元操作符 UnaryOperator<Boolean> unaryOperation = (flag)->{ return !flag; }; System.out.println(unaryOperation.apply(true)); BinaryOperator<Integer> binaryOperator = (x, y)->x*y; int result = binaryOperator.apply(999, 9999); System.out.println(result); } }
测试使用的实体类
public class Dog { private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Dog [name=" + name + ", age=" + age + "]"; } }
自定义函数式接口
@FunctionalInterface public interface Creat<T> { public T creat(String name, int age); }
运行截图就不放了,感兴趣的可以试一下。
说明
我这里直接使用 Lambda 创建了对象,然后调用了这个对象的方法(就是lambda 的代码块部分),真正使用的时候,都是直接传递 Lambda 表达式的,这种方法并不推荐,但是可以让我们很好的理解为什么? 可以看出来,Lambda 表达式的作用,最后还是需要调用 重写的抽象方法的,只不过使用表达更加清晰,简化了代码。
例如:
List<Dog> dogs = new ArrayList<>(); dogs.add(new Dog("大黄", 2)); dogs.add(new Dog("小黑", 3)); dogs.add(new Dog("小哈",1)); //将行为像数据一样传递,使用集合的 forEach 方法来遍历集合, //参数可以是一个 Lambda 表达式。 Consumer<? super Dog> con = (e)->{ System.out.println(e); }; dogs.forEach(con); System.out.println("--------------------------\n"); //直接传递 Lambda 表达式,更加简洁 dogs.forEach(e->System.out.println(e)); System.out.println("--------------------------\n"); //使用方法引用,进一步简化(可以看我的另一篇关于方法引用的博客) dogs.forEach(System.out::println); System.out.println("--------------------------\n"); //使用 Lambda 对集合进行定制排序,按照年龄排序(从小到大)。 dogs.sort((e1, e2)->e1.getAge()-e2.getAge()); dogs.forEach(System.out::println);
可以看出来,通过使用 Lambda 表达式可以,极大的简化代码,更加方便的操作集合。值得一提的是:Lambda 表达式 和 Stream 的结合,可以拥有更加丰富的操作,这也是下一步学习的方向。
运行截图:
Atas ialah kandungan terperinci Analisis contoh penggunaan ungkapan Java Lambda. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!