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<employee> 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表達式並不會對性能有多大的提升
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章