學習札記-Java8系列-2-Lambda表達式-敲開函數(shù)式編程的大門
面向?qū)ο蟮氖`
在正式講Lambda表達式和函數(shù)式編程之前我們先完成一個需求分析一下我們之前面向?qū)ο缶幊痰牟蛔悖?/p>
需求:啟動一個線程并輸出一句話
@Test
public void testTradition() throws Exception {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("使用傳統(tǒng)方式開啟線程");
}
}).start();
}
本著“萬物皆對象”的思想,創(chuàng)建一個Runnable接口的匿名內(nèi)部類對象(線程對象)來指定任務內(nèi)容肤寝,再啟動該線程始衅。這種做法是Ok的,但是……
我們真的想創(chuàng)建一個匿名內(nèi)部類對象嗎?
不兔辅。我們只是為了做這件事情而不得不創(chuàng)建一個對象数初。
我們真正希望做的事情是:將 run方法方法體內(nèi)的代碼傳遞給Thread類鹤啡。
傳遞并執(zhí)行這一段代碼肌稻,才是我們真正的目的清蚀。
而創(chuàng)建對象只是受限于面向?qū)ο笳Z法而不得不采取的一種手段方式。
那爹谭,有沒有更加簡單的辦法枷邪?
如果我們將關注點從“怎么做”回歸到“做什么”的本質(zhì)上,就會發(fā)現(xiàn)只要能夠更好地達到目的诺凡,過程與形式其實并不重要东揣。
函數(shù)式編程的解放
函數(shù)式編程思想讓我們更加關注我們的目標也就是:“做什么”
@Test
public void testLambda() throws Exception {
new Thread(()->System.out.println("使用Lambda方式開啟線程")).start();;
}
這段代碼和剛才的執(zhí)行效果是完全一樣的。
從代碼的語義中可以看出:我們啟動了一個線程腹泌,而線程任務的內(nèi)容以一種更加簡潔的形式被指定救斑。
瞬間感覺得到了解放!不再有“不得不創(chuàng)建 Runnable接口對象”的束縛真屯,不再有“覆蓋重寫抽象方法”的負擔,就是這么簡單穷娱!
總結(jié):
Java語言一大特點與優(yōu)勢就是面向?qū)ο蟀竽瑁请S著技術的發(fā)展,我們會發(fā)現(xiàn)面向?qū)ο笏枷朐谀承﹫鼍跋虏⒎鞘亲顑?yōu)的思想泵额。能夠簡單快速滿足需求配深、達到目標效果的思想有時候可能更加適合。這種思想就是函數(shù)式編程思想嫁盲!Java8中的Lambda表達式就可以讓我們把這種思想發(fā)揮的淋漓盡致篓叶!
感覺不過癮烈掠?那我們再來幾個案例對比下!
感受函數(shù)式編程的魅力-應對不斷變化的需求
需求:
根據(jù)用戶提出的不同條件篩選出滿足相應條件的商品缸托,比如:
篩選出所有名稱包含手機的商品
篩選出所有價格大于1000的商品
準備工作
方式一:傳統(tǒng)做法
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Long id; //商品編號
private String name; //商品名稱
private Double price;; //商品價格
}
//需求:篩選出所有名稱包含手機的商品
//需求:篩選出所有價格大于1000的商品
public class MagicLambda {
private List<Product> products = new ArrayList<>();
@Before
public void init(){
products.add(new Product(1L,"蘋果手機",8888.88));
products.add(new Product(2L,"華為手機",6666.66));
products.add(new Product(3L,"聯(lián)想筆記本",7777.77));
products.add(new Product(4L,"機械鍵盤",999.99));
products.add(new Product(5L,"雷蛇鼠標",222.22));
}
}
我們先使用傳統(tǒng)Java編程完成以下幾個需求,代碼如下:
//需求:篩選出所有名稱包含手機的商品
public List<Product> filterProductByName(List<Product> products){
List<Product> list = new ArrayList<>();
for (Product product : products) {
if (product.getName().contains("手機")) {
list.add(product);
}
}
return list;
}
//需求:篩選出所有價格大于1000的商品
public List<Product> filterProductByPrice(List<Product> products){
List<Product> list = new ArrayList<>();
for (Product product : products) {
if (product.getPrice() > 1000) {
list.add(product);
}
}
return list;
}
@Test
public void test1() throws Exception {
//List<Product> list = filterProductByName(products);
List<Product> list = filterProductByPrice(products);
for (Product product : list) {
System.out.println(product);
}
}
完成需求后我們發(fā)現(xiàn)了問題左敌,針對不同的需求我們要寫不同的方法實現(xiàn),而每一個不同的實現(xiàn)我們需要編寫不同的方法俐镐,這里是不是可以使用策略設計模式優(yōu)化一下矫限?
完成需求后我們發(fā)現(xiàn)了問題,針對不同的需求我們要寫不同的方法實現(xiàn)佩抹,而每一個不同的實現(xiàn)我們需要編寫不同的方法叼风,這里是不是可以使用策略設計模式優(yōu)化一下?
方式二:使用策略設計模式優(yōu)化
編寫策略接口
public interface MyPredicate<T> {
boolean test(T t);
}
編寫策略實現(xiàn)類
public class FilterProductByName implements MyPredicate<Product> {
@Override
public boolean test(Product t) {
return t.getName().contains("手機");
}
}
public class FilterProductByPrice implements MyPredicate<Product> {
@Override
public boolean test(Product t) {
return t.getPrice() > 1000;
}
}
修改方法實現(xiàn)
修改方法實現(xiàn)
public List<Product> filterProduct(List<Product> products,MyPredicate<Product> predicate){
List<Product> list = new ArrayList<>();
for (Product product : products) {
if (predicate.test(product)) {
list.add(product);
}
}
return list;
}
@Test
public void test2() throws Exception {
List<Product> list = filterProduct(products, new FilterProductByName());
//List<Product> list = filterProduct(products, new FilterProductByPrice());
for (Product product : list) {
System.out.println(product);
}
}
到這里我們又發(fā)現(xiàn)要針對不同的需求寫不同的策略類棍苹!很麻煩无宿!可不可以不寫?--使用匿名內(nèi)部類優(yōu)化枢里!
方式三:使用匿名內(nèi)部類優(yōu)化
@Test
public void test3() throws Exception {
List<Product> list = filterProduct(products, new MyPredicate<Product>() {
@Override
public boolean test(Product t) {
return t.getName().contains("手機");
}
});
for (Product product : list) {
System.out.println(product);
}
}
到這里我們感覺還是很麻煩孽鸡!僅僅是想執(zhí)行一個比較判斷的條件表達式!卻要創(chuàng)建接口的匿名對象重寫抽象方法坡垫!很不爽梭灿,怎么辦?--使用Lambda表達式
方式四:使用Lambda表達式優(yōu)化
@Test
public void test4() throws Exception {
filterProduct(products, (p) -> p.getPrice() > 1000).forEach(System.out::println);
}
到這里是不是已經(jīng)漸漸感受到了Lambda表達式的強大了冰悠?接下來更會讓你愛上她的堡妒!--使用Stream
(總結(jié)下:Lambda表達式可以理解為是一個匿名函數(shù),也就是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進行傳遞)溉卓∑こ伲可以寫出更簡潔、更靈活的代碼桑寨。作為一種更緊湊的代碼風格伏尼,使Java的語言表達能力得到了提升。)
方式五:使用Stream AP優(yōu)化
//獲取價格從高到低排行前三的商品信息
@Test
public void test5() throws Exception {
//products.stream().filter(p -> p.getName().contains("蘋果")).forEach(System.out::println);
//獲取價格從高到低排行前三的商品信息
products.stream().sorted((x,y) -> y.getPrice().compareTo(x.getPrice())).limit(3).forEach(System.out::println);
}
到這里是不是已經(jīng)充分感受到了Java8函數(shù)式編程的強大和魅力了尉尾?那下一篇來我們就來揭下她神秘的面紗爆阶!