Lambda表达式详解

首先,我们来谈一谈为什么java jdk8会引入lambda表达式,下面我们定义一个功能,

public class Person {
	
	public  enum Sex {
		man,woman
	}
	private String name;
    private LocalDate birthday;
    private Sex gender;
    private String emailAddress;
    private int age;
    ......set......get  method
}

然后上我们的主业务代码:

public static void main(String[] args) {
		List<Person> linkedList = new LinkedList<>();
		linkedList.add(new Person("weijinhao",null,Person.Sex.man, "740876747@qq.com", 10));
		linkedList.add(new Person("liuyawei",null,Person.Sex.man, "111111111@qq.com", 13));
		printPersonsOlderThan(linkedList, 10);
	}
	/*
	 * 该函数算是我们的主要业务,再者里面我们进行集合的遍历,并筛选出相关的元素,然后执行相关的操作。
	 * 我们的lambda表达式主要是就是优化这边。
	 */
	public static void printPersonsOlderThan(List<Person> list,int age) {
		
		 for (Person p : list) {
		        if (p.getAge() >= age) {
		            System.out.println(p.toString());
		        }
		 }
	}
}

好,这个业务也是可以实现的,但是我们要是想更换筛选条件的话怎么办,重新写代码实现吗?当然不是,我们可以分出一个

只包含test函数的接口,然后用内部类去实现筛选。

public static void main(String[] args) {
		List<Person> linkedList = new LinkedList<>();
		linkedList.add(new Person("weijinhao",null,Person.Sex.man, "740876747@qq.com", 10));
		linkedList.add(new Person("liuyawei",null,Person.Sex.man, "111111111@qq.com", 13));
		//此处我们使用匿名内部类来实现筛选业务的分离
		printPersonsOlderThan(linkedList, new CheckPerson() {
			@Override
			public boolean test(Person p) {
				//相关筛选的分离
				return p.getGender() == Person.Sex.man
		                && p.getAge() > 10
		                && p.getAge() < 25;
				
			}
		});
	}
	/*
	 * 该函数算是我们的主要业务,再者里面我们进行集合的遍历,并筛选出相关的元素,然后执行相关的操作。
	 * 我们的lambda表达式主要是就是优化这边。
	 */
	public static void printPersonsOlderThan(List<Person> list,CheckPerson test) {
		
		 for (Person p : list) {
		        if (test.test(p)) {
		            System.out.println(p.toString());
		        }
		 }
	}

但是这样看起来是不是纷繁复杂呢,现在就是Lambda表达式发挥水平的时候了。

public static void main(String[] args) {
		List<Person> linkedList = new LinkedList<>();
		linkedList.add(new Person("weijinhao",null,Person.Sex.man, "740876747@qq.com", 10));
		linkedList.add(new Person("liuyawei",null,Person.Sex.man, "111111111@qq.com", 13));
		//此处我们使用匿名内部类来实现筛选业务的分离
		printPersonsOlderThan(linkedList, /*Lambda表达式*/ (Person p) ->  
				p.getGender() == Person.Sex.man
		        && p.getAge() > 10
		        && p.getAge() < 25
		);
	}

看到了吗,我们可以实现一样的操作,但是不需要匿名内部类那样复杂。这里需要提到的时,Lambda表达式实现的基础是函数式接口,对滴,就是我们前面抽取的CheckPerson接口,下面我们在提函数式接口的格式。这里先不管。

接下来我们接着优化。

难道我们要想使用Lambda表达式就必须得自己写一个函数式接口吗,那也太费劲了吧,你想到了,人家也能想到,早就给你定义出来了一堆标准函数式接口,你直接拿过来用就ok了,他们在java.util.function包当中。在用时找到适合自己的就行了。下面我们就使用标准函数式接口来实现吧。

/*
	 * 该函数算是我们的主要业务,再者里面我们进行集合的遍历,并筛选出相关的元素,然后执行相关的操作。
	 * 我们的lambda表达式主要是就是优化这边。
	 */
	public static void printPersonsOlderThan(List<Person> list,Predicate<Person> test) {
		
		 for (Person p : list) {
		        if (test.test(p)) {
		            System.out.println(p.toString());
		        }
		 }
	}

然后看看还有什么需要优化的,这里我们可不可以把我们的相关操作拿出来呢,首先我们去标准函数式包中查找适合我们的函数接口。

public static void main(String[] args) {
		List<Person> linkedList = new LinkedList<>();
		linkedList.add(new Person("weijinhao",null,Person.Sex.man, "740876747@qq.com", 10));
		linkedList.add(new Person("liuyawei",null,Person.Sex.man, "111111111@qq.com", 13));
		//此处我们使用匿名内部类来实现筛选业务的分离
		printPersonsOlderThan(
				linkedList, 
				/*Lambda表达式*/ 
				(Person p) ->  p.getGender() == Person.Sex.man
					        && p.getAge() > 10
					        && p.getAge() < 25,
					 
		        (Person p) -> System.out.println(p.toString())
		);
	}
	/*
	 * 该函数算是我们的主要业务,再者里面我们进行集合的遍历,并筛选出相关的元素,然后执行相关的操作。
	 * 我们的lambda表达式主要是就是优化这边。
	 */
	public static void printPersonsOlderThan(List<Person> list,Predicate<Person> test,Consumer<Person> operation) {
		
		 for (Person p : list) {
		        if (test.test(p)) {
		           // System.out.println(p.toString());
		        	operation.accept(p);//我们把操作也拿出来了
		        }
		 }
	}

那但是感觉还是不够通用,如果我们加上泛型的话感觉会更好。

public static<T> void printPersonsOlderThan(Iterable<T> list,Predicate<T> test,Consumer<T> operation) {
		
		 for (T p : list) {
		        if (test.test(p)) {
		           // System.out.println(p.toString());
		        	operation.accept(p);//我们把操作也拿出来了
		        }
		 }
	}

ok,我们最终的函数就形成了。就这事泛型和Lambda的功能。

既然Lambda这麽强大,下面我们就来说说Lambda的格式:

java当中使用Lambda表达式的前提是:必须有函数式接口(有且仅有一个抽象方法的接口,叫做函数式接口)。

那么如何才能万无一失的检测一下当前的接口是不是函数式接口呢?我们可以使用注释

用一个固定的格式写在public interface 之前一行即可。

@FunctionalInterface
public interface className {
} 

好了,我们来看看Lambda表达式的基本格式

//用逗号分隔的括号内的形式参数列表(type param1,type param2) -> {代码块}

我们可以忽略参数的类型,如果只有一个参数的话可以忽略大括号;

代码块中只有单句的话可以去掉{ } ,如果我们需要返回表达式的值,使用return(如果是单句的话,可以忽略return ,java会计算表达式,并返回代码块的值)

Lambda表达式在作用域中访问本地变量

像内部类一样,Lambda表达式可以抓取本地变量,但是需要注意的是,Lambda表达式在使用时不具有隐藏同名变量的作用域功能,还有就是他不能获取父类或相关类的变量,让我们附上一段代码来测试一下:

public class LambdaScopeTest {
	private int x = 0;
	public class FirstLevel {
		int x = 1;
		public void methodInFirstLevel(int x) {
			Consumer<Integer> consumer = y -> //如果我们在此使用x的话会报错,
			//这是应为Lambda表达式在使用时不具有隐藏同名变量的作用域功能
			{
				System.out.println("x:" + x); //这里的访问和内部类一样,但是不能关联更深的层次
				System.out.println("y:" + y);
				System.out.println("this.x:" + this.x);
				System.out.println("LambdaScopeTest.x:" + LambdaScopeTest.this.x);
			};
			consumer.accept(x);								
		}
	}
}
	public static void main(String[] args) {
		LambdaScopeTest lambdaScopeTest = new LambdaScopeTest();
		LambdaScopeTest.FirstLevel firstLevel = lambdaScopeTest.new FirstLevel();
		firstLevel.methodInFirstLevel(23);
	}

下面我们查看一下打印的结果:

//和我们介绍的一样
x:23
y:23
this.x:1
LambdaScopeTest.x:0

下面我们在来介绍一下目标类型

我们的Lambda表达式可以应用到随意的函数式接口吗?答案是不能,这是应为java编译器会根据Lambda表达式的上下文环境去判断,但是我们可以大体的认为是根据参数和返回值去确定。

好了这就是Lambda表达式的全部介绍了,谢谢大家的耐心观看!分享技术,感悟人生!




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值