java 8的lambda表达式
众所知周,java是一个面向对象的语言,除了部分的简单数据类型,在java中的一切都是以对象的形式存在,即使数组也是一种对象,每个类创建的实例也都是对象。在Java中定义的函数或方法是不可能完全独立的,也不能将方法作为参数或返回一个方法的实例。
而在java8之前,如若我们想要把某些功能传递给某个方法去,就是要去写一个匿名的内部类。
在java的发展过程当中,对功能的传递有着以下的方式
package com.wang.javaforword.lambda;
import java.util.Arrays;
import java.util.Comparator;
//lambda 诞生的背景
//java中的方法都是包含在对象当中,不能独立的当做参数传递
public class Demo {
public static void main(String[] args) {
String[] arr = {"b", "c", "a", "d"};
Arrays.sort(arr); //本身是升序的排列方式
System.out.println(Arrays.toString(arr));
}
}
默认的情况下是按照一个升序的方式进行排列的
那么我们现在想将这个排列的方式改为一降序的方式进行排列。就要写一个方法,进过这个方法对排序的方式进行改变。
package com.wang.javaforword.lambda;
import java.util.Arrays;
import java.util.Comparator;
//lambda 诞生的背景
//java中的方法都是包含在对象当中,不能独立的当做参数传递
public class Demo {
public static void main(String[] args) {
String[] arr = {"b", "c", "a", "d"};
Arrays.sort(arr,new StringCom());
//可以创进来一个比较器,自定义的一种排序比较
System.out.println(Arrays.toString(arr));
}
}
package com.wang.javaforword.lambda;
import java.util.Comparator;
/*创建一个字符串排序的一个类*/
public class StringCom implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);//降序比
}
}
因为只需要在这个地方需要这么一个比较器,所以我们就可以将它写为一个内部类的形式。
package com.wang.javaforword.lambda;
import java.util.Arrays;
import java.util.Comparator;
//lambda 诞生的背景
//java中的方法都是包含在对象当中,不能独立的当做参数传递
public class Demo {
public static void main(String[] args) {
String[] arr = {"b", "c", "a", "d"};
Arrays.sort(arr,new StringCom1());
System.out.println(Arrays.toString(arr));
}
//创建一个内部类的一个东西,就不需要在外部创建一个类
static class StringCom1 implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
}
}
再经过发展,我们可以将其写成一个匿名的内部类形式。
package com.wang.javaforword.lambda;
import java.util.Arrays;
import java.util.Comparator;
//lambda 诞生的背景
//java中的方法都是包含在对象当中,不能独立的当做参数传递
public class Demo {
public static void main(String[] args) {
String[] arr = {"b", "c", "a", "d"};
//匿名内部类 new + 接口/抽象类 创建一个匿名内部类的对象
Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println(Arrays.toString(arr));
}
}
在之上的例子中,为了对数组(集合)进行排序,我们为Comparator接口创建一个它的匿名内部类对象,重写接口中的方法,来实现排序的功能。
简而言之,在java中将普通的方法或函数像参数一样传递是并不简单的,为此,在java8之后中,增加了一个语言级的新特性,名为lambda的表达式。
什么是lambda的表达式
lambda表达式是一个匿名的函数,我们可以把lambda表达式理解为一段可以传递的代码(将代码看作是参数一样进行传递)。
使用它可以让我们写出更为简洁、灵活的代码。作为一种更紧凑的代码风格,使java语言的表达能力得到很大的提升。
lambda表达式的本质上只是一个 “语法糖”,有编译器推断并帮助你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。
语法糖: 也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
lambda的一些简单语法
java中的lambda表达式通常使用 (argument) -> {body}
(参数)->{ 函数体 }
左侧:lambda 表达式的参数列表
右侧:lambda 表达式中需要执行的功能,即 lambda 体
(arg1, arg2…) -> { body }
(type1 arg1, type2 arg2…) -> { body }
表达式参数类型是可以不写,jvm 可以根据上下文进行类型推断
以下就是一些lambda表达式的例子:
- 无参数,无返回值,lambda 体中只有一行代码时,{}可以忽略
( ) -> System.out.println ( “Hello World” ); - 无参数,有返回值
() -> { return 3.1415 }; - 有参数,无返回值
(String s) -> { System.out.println(s); } - 有一个参数,无返回值
s -> { System.out.println(s); } - 有多个参数,有返回值
(int a, int b) -> { return a + b; } - 有多个参数,表达式参数类型可以不写,jvm 可以根据上下文进行类型推断
(a, b) -> { return a - b; }
lambda表达式的结构
● lambda表达式可以具有零个,一个或多个参数。
● 可以显示声明参数的类型,也可以由编译器自动从上下文推断参数的类型。Lambda表达式会帮助我们推断出这个参数的类型。
例如(int a,int b)就可以写成(a,b)
● 参数用小括号括起来,用逗号分隔。例如 (a, b) 、 (int a, int b) 或 (String a, int b, float c)构成。
● 空括号用于表示一组空的参数。例如 () -> 42。
● 当有且仅有一个参数时,如果不显式指明类型,则不必使用小括号。
例如 a -> return a*a。
● Lambda 表达式的正文可以包含零条,一条或多条语句。
● 如果 Lambda 表达式的正文只有一条语句,则大括号可不用写,且表达式 的返回值类型要与匿名函数的返回类型相同。
● 如果 Lambda 表达式的正文有一条以上的语句必须包含在大括号(代码块) 中,且表达式的返回值类型要与匿名函数的返回类型相同。
Lambda表达式中的正文实现的接口中只能有一个抽象方法。(因为它省略的匿名内部类中的方法名)
功能接口(Functional interface)
在有些接口类中,会有@FunctionalInterface这个标签的存在,是功能接口的意思。
功能接口是 java 8 中的新增功能,加上这个标签就意思为在这个接口中,只能有一个抽象方法,如果出现两个以上的话,就会在编译的时候就会报错。这些接口也称为单抽象方法接口。
这些也可以使用 Lambda 表达式,方法引用和构造函数引用来表示。Java 8 也引入了一个注释,即@FunctionalInterface,当你注释的接口违反了 Functional Interface 的契约时,它可以用于编译器级错误。
一般情况在接口上看到写有@FunctionalInterface,表示这个接口是为lambda打造的
Lambda中的核心思想就是将接口中的函数当做参数一样进行传递。(在使用Lambda的时候有要求到这个接口中的抽象方法只有一个)
Lambda 表达式的例子
- 线程初始化
● 匿名内部类方式
new Thread(new Runnable() {
@Override
public void run() {
}
});
● Lambda 表达式方式
new Thread(()->{
System.out.println("apple");
});
- 事件处理
● 匿名内部类方式
JButton jButton = new JButton("按钮");
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
● Lambda 表达式方式
JButton jButton = new JButton("按钮");
jButton.addActionListener((e -> {
System.out.println("demo");
}));
- 遍历输出
输出给定数组的所有元素的简单代码。请注意,还有一种使用 Lambda 表达式的方式。
● 普通方式
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for (Integer n : list) {
System.out.println(n);
}
● 使用 -> 的 Lambda 表达式
list.forEach(n -> System.out.println(n));