java8中的lambda表达式理解

Java8在2014年3月发布,但是作为IT公司往往不是追求技术的新,而且追求技术的稳定。所以大多用的之前的版本。

Java 8 新特性简介


  • 速度更快(1、修改底层数据结构:如HashMap(数组-链表-红黑树),HashSet,ConcurrentHashMap(CAS算法)
    2、修改垃圾回收机制:取消堆中的永久区(PremGen)->回收条件苛刻,使用元空间(MetaSpace)->直接使用物理内存->加载类文件)
  • 代码更少(增加了新的语法Lambda表达式)
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常 Optional容器类

下面是个人对Lambda表达式的一些认识:

1、lambda表达式最大的作用就是简化了我们的代码编写,使我们的代码更加的优雅。但是他并不能对于程序效率提升多少。
2、我个人感觉lambda表达式像是对内部类做了简化,在需要使用内部类的地方,不需要再去 new 一个内部类了,仅仅只需要写内部类中最核心的代码就可以了。像是一个匿名方法一样,只用写参数和方法实现!

代码示例


**需求:**现在有一个List集合 List empsemployee代表员工),现在要求筛选出该集合中的员工年龄大于40岁的所有员工!

Employee.java

public class Employee {
	private int id;
	private String name;
	private int age;
	private double salary;
	}

我们首先想到的方法可能是,写一个方法,直接将 emps 集合进行遍历,然后判断年龄是否大于40岁,如果是则加入新的list集合中,遍历完成以后就将新的list集合返回即可。如下:

public List<Employee> filterEmployeeAge(List<Employee> emps){
		List<Employee> list = new ArrayList<>();

		for (Employee emp : emps) {
			if(emp.getAge() <= 35){
				list.add(emp);
			}
		}
		return list;
	}

这样做似乎没什么问题,但是现在又有一个新的需求了,现在需要过滤出薪水 salary 大于3000的所有员工,于是乎我们又需要编写一个通过员工薪水过滤的方法!如下:

public List<Employee> filterEmployeeSalary(List<Employee> emps){

		List<Employee> list = new ArrayList<>();
		for (Employee emp : emps) {
			if(emp.getSalary() >= 5000){
				list.add(emp);
			}
		}
		return list;
	}

这样做也没什么问题,但是现在又有一个新的需求了,现在需要过滤出员工id大于500的所有员工,于是我们又需要编写一个通过员工id过滤的方法!如下:

public List<Employee> filterEmployeeId(List<Employee> emps){

		List<Employee> list = new ArrayList<>();
		for (Employee emp : emps) {
			if(emp.getId() >= 5000){
				list.add(emp);
			}
		}
		return list;
	}

1、写着写着我们就开始发现问题了,所编写的几个方法中代码逻辑都一样,只有一行判断条件不同。我们写了很多的冗余代码。
2、我们可能还会通过员工姓名、生日、爱好、家庭地址、电话号码等等信息来过滤员工。那么我们就需要编写一个又一个的重复方法。这样就使得我们的代码变得冗余极其不优雅。所以我们需要进行改进。

改进方案


方案1(策略模式)

通过策略设计模式来对我们的代码进行改进,首先我们定义一个过滤的方法,你需要通过什么条件进行过滤员工,那么将你的过滤策略通过方法的形参传入进来即可。在方法的内部会自动的根据你传入的策略进行过滤员工。
通过策略模式,我们知道我们首先需要去定义一个策略接口,每一个实现了该接口的类都是一个策略。如下:

@FunctionalInterface
public interface MyPredicate<T> {
	public boolean test(T t);
}

现在我们要通过员工的id来过滤员工,过滤出员工id大于500的所有员工,所以我们要去定义一个策略实现类,继承自定义的接口MyPredicate。在实现类中覆写test方法去指定具体过滤策略。如下:

public class FilterEmployeeForId implements MyPredicate<Employee>{
	//通过员工id过滤员工策略
	@Override
	public boolean test(Employee t) {
		return t.id() > 500;
	}
}

然后在编写一个过滤方法,通过传入的过滤策略来过滤员工。如下:

public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){
		
		List<Employee> list = new ArrayList<>();
		for (Employee employee : emps) {
			if(mp.test(employee)){
				list.add(employee);
			}
		}
		return list;
	}

在我们调用该方法来按条件过滤员工时,我们只需要传入实现了策略接口的具体实现类即可。如下:

@Test
	public void test(){
		List<Employee> list = filterEmployee(emps, new FilterEmployeeForId());
		for (Employee employee : list) {
			System.out.println(employee);
		}
	}

如果,现在又需要通过年龄过滤,过滤出年龄小于40岁的员工。那么我们只需要再定义一个具体策略类去实现策略接口MyPredicate即可。然后在调用的时候传入该策略实现类即可。不用再去写一个for循环遍历emps集合然后通过年龄做判断了。

但是如果这样做的话,每当我们要增加一个过滤需求,我们都需要自己去定义一个策略实现类然后实现策略接口,这样也显得比较麻烦!所以还需要进行改进!

方案2(匿名内部类)

我们仍然需要编写一个策略接口,但是当我们要通过具体xxx条件去过滤员工的时候,我们不用再自己去定义一个类然后实现他的策略方法了。我们可以直接通过匿名内部类完成。在匿名内部类中实现具体的策略!比如现在要过滤出员工id小于500的员工。如下:

@Test
	public void test5(){
		List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
			//匿名内部类中实现具体的策略
			@Override
			public boolean test(Employee t) {
				return t.getId() <= 500;
			}
		});

		for (Employee employee : list) {
			System.out.println(employee);
		}
	}

如果我们现在又要过滤出员工年龄小于40的所有员工,那么只需要改动匿名内部类中的过滤条件即可。但是这样的话,每一个不同的过滤条件仅仅是匿名内部类中的判断条件不同,其他的部分还是都是一样的(比如new MyPredicate() { xxx }),这样代码仍然不优雅,我们还需要做一定的修改。所以就引出了lambda表达式。

方案3(lambda表达式)

从方案2中我们看到了,每一个不同的过滤需求,其实只有匿名内部类中的一小部分改动,其他都是一样的。但是我们每次都要去手动创建匿名内部类。如果我们每次能只写过滤的核心条件就可完成员工的过滤多好呀!lambda表达式为我们做到了这一点。继方案2,使用lambda表达式,我们只需要传入核心的判断条件即可。如下:

public void test(){
		List<Employee> list = filterEmployee(emps, (e) -> e.getId() <= 500);
		list.forEach(System.out::println);
	}

**说明:**在上面的代码中我们看到了,lambda表达式仅仅通过一行代码((e) -> e.getId() <= 500)就表达了核心过滤条件。不用再去写匿名的内部策略类了。这里lambda表达式其实是对接口中的 test(xxx) 方法的一个实现。左边是该方法需要的参数,右边是该方法的方法体的具体内容。从上面的方案2和方案3可以看出,lambda表达式其实就是对使用匿名内部类的地方做了一个简化,我们只需要去写这个匿名内部类中的方法的具体逻辑即可,不用再去new 一个匿名内部类了,大大的简化了代码编写

总结


  • lambda表达式可以简化某些匿名内部类的写法
  • lambda表达式是匿名内部类的语法糖
  • 使用lambda表达式可以使我们的代码更加的简洁优雅
  • lambda表达式可以使代码变得简洁,如果某些地方强行使用这也可能会造成某些代码的可读性降低
  • lambda表达式并不会对性能有多大的提升

你可能感兴趣的:(java常见知识,Java中lambda表达式)