Java8之lambda表达式

前言

从Java8开始,我们迎来了一个重要特性,那就是Java开始支持lambda表达式,从此Java开始了面向函数编程的道路。这其实给我们的编程方式带来了一定的改变。例如:
Java8之前,如果要遍历一个集合我们大概的写法是这样的:

		for (String str : list) {
			System.out.println(str);
		}

但从Java8开始,我们遍历一个集合的方式大概可以是这样的:

list.forEach((str) -> System.out.println(str));

甚至可以是这样的:

list.forEach(System.out::println);

有没有很激动?有没有很惊喜?
虽然上述实例似乎没有什么大的用处,但至少可以看出,lambda表达式的引入,大大简化了我们的开发,有的童鞋可能会问了,这个似乎也没有什么大的帮助嘛。也少不了几行代码。莫要方,请听我细细道来。

一个简单的程序问题

我需要实现如下需求,一个人有三门功课(语文、数学、英语),统计各科成绩的总分,我们写出来的代码大概是这样的:
下面展示一些 内联代码片

		List<Achievement> list = Arrays.asList(new Achievement("三毛", 90, 85, 87), new Achievement("张嘎", 70, 55, 0),
				new Achievement("张嘎", 90, 30, 82));
		
		// 统计语文成绩
		int sumChinese = 0;
		for (Achievement a : list) {
			sumChinese += a.getChinese();
		}
		System.out.println(sumChinese);
		// 统计数学成绩
		int sumMath = 0;
		for (Achievement a : list) {
			sumMath += a.getMath();
		}
		System.out.println(sumMath);
		// 统计英语成绩
		int sumEnglish = 0;
		for (Achievement a : list) {
			sumEnglish += a.getEnglish();
		}
		System.out.println(sumEnglish);

看到上面的代码之后你是不是觉得也不是那么优雅。也许很多童鞋觉得反射可能是个不错的选择,今天不用反射,我们使用另外一种解决方法,使用接口定义。
改造之后的代码可能是这样的。

public static void main(String[] args) {
		List<Achievement> list = Arrays.asList(new Achievement("三毛", 90, 85, 87), new Achievement("张嘎", 70, 55, 0),
				new Achievement("张嘎", 90, 30, 82));
		
		// 统计语文成绩
		System.out.println(sum(list, new ValDefine() {
			@Override
			public int getValue(Achievement a) {
				return a.getChinese();
			}
		}));
		// 统计数学成绩
		System.out.println(sum(list, new ValDefine() {
			@Override
			public int getValue(Achievement a) {
				return a.getMath();
			}
		}));
		// 统计英语成绩
		System.out.println(sum(list, new ValDefine() {
			@Override
			public int getValue(Achievement a) {
				return a.getEnglish();
			}
		}));
	}
	
	private static int sum(List<Achievement> list, ValDefine valDefine) {
		// 统计总成绩
		int sum = 0;
		for (Achievement a : list) {
			sum += valDefine.getValue(a);
		}
		return sum;
	}
	
	public static interface ValDefine {
		public int getValue(Achievement a);
	}

看着这一大段的内部类代码顿时就觉得头疼。

所以仍然是上述的例子,我们用lambda表达式进行相应的修改,效果如下:
下面展示一些 内联代码片

		// 统计语文成绩
		System.out.println(sum(list, (a) -> {
			return a.getChinese();
		}));
		// 统计数学成绩
		System.out.println(sum(list, (a) -> {
			return a.getMath();
		}));
		// 统计英语成绩
		System.out.println(sum(list, (a) -> {
			return a.getEnglish();
		}));

从上述例子我们可以看出,lambda表达式式简化接口实例化的一种手段。当然他的作用并不止如此。接下来我们就将讲解下lambda表达式的使用了。

lambda表达式的语法

首先lambda表达式是对接口的简化,但并不是所有的接口都可以用lambda表达式表示,lambda表达式只能支持一个接口有且仅有一个方法的接口,例如:java.lang.Runnable。为了避免我们定义的接口出现问题,我们可以在接口上标注@java.lang.FunctionalInterface,这个样当我们在这样的接口在定义了多个方法的时候就会直接报错。
关于lambda表达式的语法,我接下来就以上例中的ValDefine为例讲解。
首先,一种常见的写法应该是这样的:

		(Achievement a) -> {
			return a.getChinese();
		}

当然上例中也看到了。参数的类型可以省去,就成了这样的:

		(a) -> {
			return a.getChinese();
		}

如果像本例中的场景,只是简单的返回,那么你可以写成这样:

		(a) -> a.getChinese()

都是lambda表达式,似乎差距还不小。你以为这就没有了,其实并不是。还记得这段代码吗?

list.forEach(System.out::println);

forEach方法的参数是一个Consumer,之所以可以这么写,那是应为当返回值为零时,我们可以直接用 对象::方法名 的方式表示,这样做,如果是静态方法,那么我们可以直接用 ::方法名的方式表示,例如:

	private static void print(String str) {
		System.out.println(str);
	}
	
	list.forEach(System.out::println);
	list.forEach(LambdaTest::print);

关于lambda表达式的基本语法,大概就介绍到这,接下来我们就来说一下lambda家族的常用接口。

lambda家族的常用接口

lambda家族的常用接口如下:

接口说明
java.util.function.Consumer一个参数无返回
java.util.function.BiConsumer<T, U>两个参数,无返回值
java.util.function.Function<T, R>一个参数,一个返回值
java.util.function.BiFunction<T, U, R>两个参数,一个返回值
java.util.function.Supplier无参数,一个返回值

记住了这些接口,可以让你少定义很多接口哟。

例如上述例子我们就可以这样:

	private static int sum(List<Achievement> list, Function<Achievement, Integer> valDefine) {
		// 统计总成绩
		int sum = 0;
		for (Achievement a : list) {
			sum += valDefine.apply(a);
		}
		return sum;
	}

好了,上面就是关于lambda表达式的全部内容,欢迎大家留言交流和讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值