Lambda表达式--Java8的新功能案例详解(1)

1.lambda表达式--背景知识以及相关评价:

      lambda表达式允许你通过表达式来代替功能接口。
      函数编程在C#、Python、JavaScript中都得到充分体现。而Java直到最新的Java 8才开始正式支持函数编程,最明显的改进就是对Lamba表达式的支持。正如C#之父Anders Hejlsberg在那篇文章 编程语言大趋势 中所讲,未来的编程语言将逐渐融合各自的特性,而不存在单纯的声明式语言(如之前的Java)或者单纯的函数编程语言。将来声明式编程语言借鉴函数编程思想,函数编程语言融合声明式编程特性...这几乎是一种必然趋势。
      当今世界主流编程语言无不吸纳强大的闭包概念,但有个例外,它就是Java。数年来,Java语言中增加闭包特征的工作看起来毫无进展。
早在15年之前,Scala语言和TypeSafe框架的作者Martin Odersky和Phillip Wadler发布了实验性的“Pizza”项目,由此,人们开始试图将闭包纳入编程语言的基本特征之一。尽管这看起来有点过于复杂,Java社区大概在2008年就有了接纳闭包概念的想法。但由于Oracle对Sun微系统公司的匆忙收购,Java被冷落,Java语言新版本的发布不断的被推迟。
      但在Java8中,事情有了很大的变化,Java语言终于为Java编程部队配备了闭包的武器。“也许这是Java编程语言有史以来最重要的一次升级,”Oracle的Java语言架构师Brian Goetz说。他指出,在Java中引入闭包概念对Java程序开发方法的影响甚至会大于Java5中引入的泛型特征对编程方式带来的影响。“就像泛型能使开发人员对数据类型进行抽象,Lambda的目的是让程序员能够对程序行为进行抽象。”
      Lambda这个名称来自于把闭包绑定到Java编程语言的Lambda项目。Lambda以及闭包的引入能做些什么?你可以这样想,它能够让程序员把一段程序代码当做数据一样使用。一个方法可以像定义和使用一个变量那样的方式被定义和使用,定义出的方法可以被当作参数传递到其它方法内,就像它们是一个对象实例或一个类型数据一样。“看起来这好像也没什么,但实际上它影响巨大,”Goetz说。“这将从根本上改变我们开发java程序的方式。”
      我们等待了太久,但随着Java8的发布,Lambda终于成为Java规格说明书里的正式特征之一。一种由于过于复杂而最初被传统程序员放弃的语法将最终成为一种每个现代Java应用程序里都能看到的标准技术。

2.lambda表达式--基础语法以及使用细节:

    Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口的实例。
    Lambda表达式代替匿名内部类创建对象时,Lambda表达式的代码块将会代替实现抽象方法的方法体,Lambda表达式就相当于一个匿名方法。Lambda表达式的主要作用就是代替匿名内部类的繁琐语法。
 

 *例如有如下的操作数组的接口和类:


//处理行为接口
public interface Command
{
	//封装处理行为的方法
	void process(int[] target);
}

//处理数组的类
public class ProcessArray
{
	//方法参数为处理的数组和处理命令
	public void process(int[] target,Command cmd)
	{
		cmd.process(target);
	}
}

//打印处理实现处理接口
public class PrintCommand implements Command
{
	public void process(int[] target)
	{
		for(int temp : target)
			System.out.println("迭代输出目标数组的元素:"+temp+"\t");
	}
}

//求和处理实现处理接口
public class AddCommand implements Command
{
	public void process(int[] target)
	{
		int sum=0;
		for(int temp : target)
			sum+=temp;
			System.out.println("目标数组求和的结果为:"+sum+"\t");
	}
}

Java8之前使用匿名内部类的解决方法:

//使用匿名对象和 匿名内部类实现
public class CommandTest
{
	public static void main(String[] args)
	{
		ProcessArray pa=new ProcessArray();
		int[] target={5,1,0,9,-2,10};
		
		//创建匿名对象
		pa.process(target,new PrintCommand());
		pa.process(target,new AddCommand());
		//调用处理数组的方法,具体行为取决于匿名内部类
		pa.process(target,new Command()
			{
				public void process(int[] target)
				{
					for(int temp : target)
						System.out.println("迭代输出目标数组的元素:"+temp+"\t");
				}
			}
		);
		pa.process(target,new Command()
			{
				public void process(int[] target)
				{
					int sum=0;
					for(int temp : target)
						sum+=temp;
					System.out.print("目标数组求和的结果为:"+sum+"\t");
				}
			}
		);
	}
}

Java8提供的Lambda表达式避免了使用内部类的繁琐语法:


//利用java8的Lambda表达式
public class CommandTest2
{
	public static  void main(String[] args)
	{
		ProcessArray pa=new ProcessArray();
		int[] target={5,1,0,9,-2,10};
		//处理数组,具体行为取决于内部类
		pa.process(target,(int[] arr)->
		{
			int sum=0;
			for(int tmp:target)
				sum+=tmp;
		    System.out.println("数组元素和为"+sum);
		}
		);
	}
}

 

      Lambda表达式由3部分组成:
    <1>形参列表。形参列表允许省略形参类型,如果形参列表只有一个参数,形参列表的圆括号也可以省略。
    <2>箭头(->)。
    <3>代码块。如果代码块只有一条语句,Lambda表达式允许省略代码的花括号;Lambda代码块只有一条return语    句,可以省略return关键字。

  例如如下一个完整实例演示了 Lambda表达式的简化用法:

 

interface Eatable
{
	void taste();
}
interface Flyable
{
	void fly(String weather);
}
interface Addable
{
	int add(int a,int b);
}
public class LambdaDemo
{
	//调用该方法需要Eatable对象
	public void eat(Eatable v)
	{
		System.out.println(v);
		v.taste();
	}
	//调用该方法需要Flyable对象
	public void fly(Flyable v)
	{
		System.out.println(v);
		v.fly("天气晴朗,万里无云");
	}
	//调用该方法需要Addable对象
	public void add(Addable v)·
	{
		System.out.println(v);
		System.out.println("5和3的和:"+v.add(5,3));
	}
	public static void main(String[] args)
	{
		LambdaDemo ld=new LambdaDemo();
		//Lambda表达式只有一条语句,可以省略花括号
		ld.eat(()->System.out.println("好吃!"));
		//Lambda表达式的形参列表只有一个形参,可以省略圆括号
		ld.fly(weather->
		{
			System.out.println("今天的天气是"+weather);
		}
		);
		//Lambda表达式只有一条语句,可以省略花括号,当需要返回值时,也可以省略return关键字
		ld.add((a,b)->a+b);
	}
}

    Lambda表达式的类型,也被称为目标类型(Target Type),Lambda表达式的目标类型必须是函数式接口。    函数式接口(Functional Interface)代表只包含一个抽象方法的接口,函数式接口可以有多个类方法和默认方法。java8开始提供的注释(Annotation)中的@FunctionalInterface注解,就是用于提示编译器进行函数式接口的检查。

    Java预定义了大量的函数式接口,例如Runnable、ActionListenner都是函数式接口,还有java.util.function包下也有大量的函数式接口。(Package java.util.function
    Functional interfaces provide target types for lambda expressions and method references)
    例如该包下典型的包含以下四类接口:
    <1>XxxFunction:这类接口通常用于对指定数据进行转换处理。通常包含一个apply抽象方法,该方法对参数进行处理转换,然后返回一   个新的值,例如DoubleToIntFunction 的applyAsInt方法(DoubleToIntFunctionDemo.java演示 ) 。
    <2>XxxConsumer:该接口通常包含一个apply抽象方法,与XxxFunction接口类似,只是没有返回值。
    <3>XxxPredicate:这类接口通常包含一个test()抽象方法,该方法通常用来对参数进行某种判断,用于进行筛滤数据,然后返回一个布尔值,
    <4>XxxSupplier:这类接口通常包含一个getAsXxx()抽象方法,该方法不需要参数,该方法会按照某种逻辑算法返回一个数据。

     例如java.util.function包下的DoubleToIntFunction接口的用法如下:

import java.util.function.*;
public class DoubleToIntFunctionDemo
{
	public void DoubleToInt(double d,DoubleToIntFunction dti)
	{
		int tmp=dti.applyAsInt(d);
		System.out.println(d+"----->"+tmp);
	}
	public static void main(String[] args)
	{
		DoubleToIntFunctionDemo a=new DoubleToIntFunctionDemo();
		a.DoubleToInt(1.20,(d)->
		{
			return (int)d;
		}
		);
	}
}


    技术分享


      这里只是利用几个简单的例子介绍了java的Lambda表达式,以后还会有持续更新,希望从事开发的朋友能够多多交流,不断进步!




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。