Java函数式编程基础之【Lambda表达式】语法与示例

Lambda 是一个匿名函数, Lambda 表达式是一段可以传递的代码(将代码像数据一样进行传递)。

Lambda表达式其本质是函数式接口(只有一个抽象方法)的实例。
它是可传递的匿名函数的一种形式:它没有名称,但它有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常列表。

Lambda 表达式基础语法:

Lambda表达式是Java 8 引入的一种新的语法,它以一种简洁的语法定义的语句块(代码块),常可作为函数接口实例使用。
Java引入了一个新的操作符“->”, 该操作符被称为 Lambda 操作符或箭头操作符。箭头操作符将 Lambda 分成了两个部分:
①左侧:是 Lambda 表达式的参数列表。
②右侧:是 Lambda 表达式的代码块(语句块,函数体),是函数式接口中抽象方法的方法体。
Lambda表达式有三个组成部分:参数列表、Lambda 操作符“->”、语句块。Lambda表达式的标准的语法格式如下:
(parameter-lis) -> {express-or-statements}

  • 参数列表(parameter-lis):括号中的参数列表,有多个参数时以英文逗号分隔,如没有参数需要保留括号“()”,参数可以声明类型,通常不需要声明(编译器可以根据上下文推导获得)。
  • Lambda 操作符(->):其作用是告诉编译器这是一个λ表达式。
  • Lambda表达式的语句块:花括号“{}”中的express-or-statements表示是表达式或语句块,相当于方法体。特殊情形,当只有一条语句时,可以省略花括号“{}”和语句结尾处的分号“;”,把它作为一个表达式使用。

Lambda 表达式的语法格式:

  • 格式一:无参数Lambda 表达式:表达式语法格式:() -> { 程序语句块 }
    接口名和方法名都可以省略。无参数的Lambda表达式,必须保留空的括号“()”。更特殊的情形,当只有一行程序代码时,可简写为:() -> 表达式
    无参数,无返回值的用法 示例:() -> System.out.println(“我是一个线程的Lambda版本”);

示例一:示例中Runnable r 采用匿名函数接口的版本;Runnable r1 使用Lambda 表达式版本。

	public void test1() {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println("我是一个线程");
			}
		};
		r.run();
		Runnable r1 = () -> System.out.println("我是一个线程的Lambda版本");
		r1.run();
	}

示例二:一个更复杂的例程LambdaDemo:显示当前时间,每隔1秒显示一次日期时间。
请在电脑上调试一下,看看效果。
Java 7以前版本的匿名类写法版本

import java.util.Date;	
import javax.swing.Timer;
public class LambdaDemo {
	public static void main(String[] args) {	
		new Thread( new Runnable() {//灰底代码是个匿名类,Runnable是函数接口
	  		@Override
	  		public void run()	//run是方法名
	  		{ 
	  			new Timer(1000, event->System.out.println("日期时间:" +new Date())).start(); }
			} ).start();
		
		while(true); //主线程无限循环
	}
}

Lambda表达式版本:
Java 8引入了Lambda表达式,可写出更优雅的代码,可如下改写为无参数的λ表达式,效果完全相同:

import java.util.Date;	
import javax.swing.Timer;
public class LambdaDemo {
	public static void main(String[] args) {	
		new Thread( ()->{		//改写为λ表达式后,接口名和方法名都省略了。
			new Timer(1000, event->System.out.println("日期时间:" +new Date())).start(); 
		} ).start();
		
		while(true); //主线程无限循环
	}
}

单行的Lambda表达式,还可再精简;以下是最简版本写法,仔细瞧瞧又省略了啥
注意:中间这行是表达式,不是语句,结尾处没有分号。有分号反而错了。

		new Thread( ()->	
			new Timer(1000, event->System.out.println("日期时间:" +new Date())).start()
		).start();	
  • 格式二:单个参数Lambda表达式:语法一般格式为:([类名]变量名)->{ 程序语句块 }
    格式中的方括号表示里面的内容是可选的。通常,λ表达式参数类型可推导出来,可以省略类名和参数两边的括号“()”。如实现事件监听器的Lambda表达式示例:event -> { 程序语句块 }
    当只有单条语句时,还可省略花括号,简写形式为:变量名->表达式
    上例中的run方法体中Timer构造器的第二个参数就是单个参数λ表达式的例子,但入口参数event在表达式中没有用到。下面就是简写形式:
	new Timer(1000, event->System.out.println("日期时间:" +new Date())).start();

对于打印显示的Lambda表达式:
(x) -> System.out.println(x); 或者 x -> System.out.println(x); 单个参数,可以省略参数的小括号。

	public void test2(){
		String message = "消费者Consumer函数式接口,有一个输入参数,无返回值";
		Consumer<String> con = (x) -> System.out.println(x);
		con.accept(message);
	}

例如,遍历打印字符串列表中的元素:

	List<String> list = Arrays.asList("苹果","桃子","西瓜","香蕉");
	list.forEach( k->System.out.println(k) );
  • 格式三:多参数Lambda表达式情形:多参数情形是指有二个以上参数的情况,其语法一般格式为:
    ([类名1] 变量名1,[类名2] 变量名2[,…])->{ 程序语句块 }
    如果不能推断出类名时,要声明参数类型,然后用符号“->”指向语句块。例如:
    (String str1,String str2)-> { 具体的语句 }
    (String str1,String str2)-> str1.length() – str2.length()
    通常情况下,编译器都可推断出参数的类名,类名可省略:
    (变量名1,变量名2[,…])->{ 程序语句块 }

有多行程序语句时花括号不能省略。例如:(str1,str2)-> { 具体的语句块 }
下面是字符串数组排序的示例代码,只有一行代码省略花括号和语句结束符:

		String[] array = { "Mary","Tony","John","Bob"};
		Arrays.sort( array, (a,b)->a.compareTo(b) );

再来看一个例子,有两个参数,有返回值的:(x, y) -> x + y

public void test3() {
		//用Lambda表达式给函数接口实例赋值
		BinaryOperator<Integer> binary = (x, y) -> x + y;
		System.out.println(binary.apply(1, 2));  // 3
	}
  • 语法四:Lambda表达式的返回类型无需指明,会根据上下文推导得到。如果Lambda表达式有返回值,则不能只实现部分的分支,这和普通方法的规则是相同的。
    下面这个表达式不合法,因为只有x>=0的分枝,缺少x<0分支:
	// 不正确的写法,只实现了部分分枝
	( int x ) -> { if(x>=0)return true; } 

正确的写法为: x-> return (x>=0) ? true : false

	// 正确的写法
	 x-> return (x>=0) ? true : false

Lambda 表达式参数的数据类型通常可以省略,因为大多可由编译器推断得出,称为“类型推断”。

	public void test5() {
		//直接使用Lambda 表达式,“类型推断”
		Integer sum = Arrays.asList(1, 3, 5, 2, 4).stream().reduce(0, (x, y) -> x + y);
        System.out.println("sum = "+ sum); //打印“sum = 15”
	}

可以看到,在Lambda 表达式中的参数列表,可以不用写参数的类型,称为“类型推断”。这与 java7中 new ArrayList<>(); 类似,<>棱形操作符不需要指定泛型类型,可根据上下文做类型的推断是一样道理。

  • Lambda 表达式的特殊用法:方法引用

方法引用(method references),这种语法用来替代某些特殊形式Lambda表达式。如果Lambda表达式的全部内容就是调用一个已有的方法,那么可以用方法引用来替代Lambda表达式。方法引用可以细分为四类:
在这里插入图片描述

参考文档

Java Lambda 表达式详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值