温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java8中lambda表达式的用法

发布时间:2021-08-23 23:35:01 来源:亿速云 阅读:166 作者:chen 栏目:大数据

这篇文章主要讲解了“Java8中lambda表达式的用法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java8中lambda表达式的用法”吧!

函数式接口

只含有一个抽象方法的接口,被称为函数式接口,例如Runnable、Comparator、EventHandler,可以使用lambda表达式来创建函数式接口的实例对象,例如:

Runnable task = () -> System.out.println("Hello Lambda!");  
Comparator<String> comp = (first, second) -> Integer.compare(first.length(), second.length());  
EventHandler<ActionEvent> handler = event -> System.out.println("Thanks for clicking!");

Java中的函数式接口,通常会使用 @FunctionalInterface 对接口类型进行注解。

Java lambda的作用

  • lambda表达式广义上的定义是:一个带有参数的表达式。

  • 在Java中,lambda表达式唯一的作用就是函数式接口的转换,我们写的lambda表达式,都是为了代替对函数式接口的实现,简化编码工作。

  • lambda表达式的参数列表对应函数式接口的抽象方法的参数列表,lambda表达式内容对应抽象方法实现的方法体。

Java lambda语法

语法

 (Type1 parameter1, Type2 parameter2, ..., TypeN parameterN) -> {  
	 statement1;   
	 statement2;   
	 ...  
	statementN;  
	return value;  
};

示例:

(String first, String second) -> Integer.compare(first.length(), second.length());

简化与变形

  • 如果lambda表达式没有参数,只写一对小括号(),括号内留空;

  • 如果一个lambda表达式的参数类型是可以被推导的,那么可以省略参数类型;例如:
    Comparator<String> comp = (first, second) -> Integer.compare(first.length(), second.length());

  • 如果一个lambda表达式只有一个参数,且该参数的类型是可以被推导的,那么可以省略参数类型和小括号,例如:
    EventHandler<ActionEvent> handler = event -> System.out.println("Thanks for clicking!");

补充

  • lambda表达式的参数列表本身也是要映射函数式接口抽象方法的参数列表的,所以我们可以像对待方法参数一样对待lambda表达式参数,例如:添加final修饰、添加@NonNull注解等;

  • 为了更容易地理解lambda,最好将lambda表达式想象成一个函数,而不是一个对象,并记住该函数可以被等价转换成为一个函数式接口;

方法引用

背景

想要传递给其他代码的操作已经有现成的实现方法了,想要复用已有的实现,例如:
button.setOnAction(event -> System.out.println(event));可以简化为:
button.setOnAction(System.out::println);
其中的System.out::println就是一个方法引用,需要注意的是,方法引用等同于一个lambda表达式,也是需要可以被转换为一个对应的函数式接口。再举一个例子,不区分大小写对字符串进行排序:
Arrays.sort(strings, String::compareToIgnoreCase);

3种方法引用方式

  • 类名::静态方法名,对静态方法的引用;

  • 类名::成员方法名,对第一个参数指定对象的成员方法的引用;

  • 对象::成员方法名,对指定对象成员方法的引用;

示例分别如下:
示例1:(double x, double n) -> Math::pow;
示例2:Arrays.sort(strings, String::compareToIgnoreCase);
示例3:button.setOnAction(System.out::println);

其他常用方式示例:
this::实例方法;
super::实例方法。

构造器引用

格式: 类名::new ,示例:
Button::new, int[]::new(等价于x -> new int[x])
如果有多个构造器,编译器会从中推断并挑选一个最合适的构造器。

构造器引用可用于突破Java无法构建泛型数组的限制:

List<String> lables = ...;
Stream<Button> stream = lables.stream().map(Button::new);
Button[] buttons  = stream.toArray(Button[]::new);

变量作用域

public static void repeatMessage(String text, int count) {
	Runnable r = () -> {
		for (int i=0; i < count; i++) {
			System.out.println(text);
			Thread.yield();
		}
	}
}

new Thread(r).start();

一个lambda表达式有3个部分:

  • 一段代码;

  • 参数;

  • 自由变量的值,即不是参数又没有在代码中定义的变量的值,例如上例中的:text、count;

  • 因为lambda表达式可能会再repeatMessage方法返回后执行,所以需要在方法被调用时就捕获自由变量的值并保存起来,以便在表达式执行时使用变量值;

  • 含有自由变量的代码块被称为“闭包”,所以lambda表达式就是Java的闭包,内部类也是闭包;

  • 在lambda表达式中,引用的外部变量值是不可以在表达式中被修改的,因为修改的话线程不安全,但是,此不可变的约束只做用在变量引用上,无法限制变量内部的值的修改,例如:数组元素、集合元素、或者其他实例变量的属性等;

  • lambda表达式中使用this,引用的是创建该lambda表达式的方法所在对象,而非lambda表达式对应函数式接口实现类的this;

  • lambda表达式中不允许出现与局部变量同名的变量定义;

接口默认方法

背景

为了使存量接口能够支持lambda表达式,同时又不影响已有的实现类,Java8开始支持接口的默认方法实现,这样存量接口就可以通过添加默认方法的方式来支持lambda表达式。

默认方法冲突解决规则

  • 选择父类中的方法。如果一个父类中提供了具体的实现方法,那么接口中的默认同签名方法会被忽略;

  • 接口冲突。如果一个类的一个父接口提供了一个默认方法,另一个接口中有相同签名的方法(不管是否默认方法),实现类必须覆盖该方法来解决冲突。

感谢各位的阅读,以上就是“Java8中lambda表达式的用法”的内容了,经过本文的学习后,相信大家对Java8中lambda表达式的用法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI