java1.8 新特性 - Lambda表示式
排序介面優化
先來體驗一下lambda最直觀的優點:簡潔程式碼
//匿名內部類
Comparator<Integer> cpt = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> set = new TreeSet<>(cpt);
System.out.println("=========================");
//使用lambda表示式
Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> set2 = new TreeSet<>(cpt2);
只需要一行程式碼,極大減少程式碼量!!
業務程式碼優化
這樣一個場景,在商城瀏覽商品資訊時,經常會有條件的進行篩選瀏覽,例如要選顏色為紅色的、價格小於8000千的….
// 篩選顏色為紅色
public List<Product> filterProductByColor(List<Product> list){
List<Product> prods = new ArrayList<>();
for (Product product : list){
if ("紅色".equals(product.getColor())){
prods.add(product);
}
}
return prods;
}
// 篩選價格小於8千的
public List<Product> filterProductByPrice(List<Product> list){
List<Product> prods = new ArrayList<>();
for (Product product : list){
if (product.getPrice() < 8000){
prods.add(product);
}
}
return prods;
}
我們發現實際上這些過濾方法的核心就只有if語句中的條件判斷,其他均為模版程式碼,每次變更一下需求,都需要新增一個方法,然後複製黏貼,假設這個過濾方法有幾百行,那麼這樣的做法難免笨拙了一點。如何進行優化呢?
優化一:使用設計模式
定義一個MyPredicate介面
public interface MyPredicate <T> {
boolean test(T t);
}
如果想要篩選顏色為紅色的商品,定義一個顏色過濾類
public class ColorPredicate implements MyPredicate <Product> {
private static final String RED = "紅色";
@Override
public boolean test(Product product) {
return RED.equals(product.getColor());
}
定義過濾方法,將過濾介面當做引數傳入,這樣這個過濾方法就不用修改,在實際呼叫的時候將具體的實現類傳入即可。
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
List<Product> prods = new ArrayList<>();
for (Product prod : list){
if (mp.test(prod)){
prods.add(prod);
}
}
return prods;
}
例如,如果想要篩選價格小於8000的商品,那麼新建一個價格過濾類既可
public class PricePredicate implements MyPredicate<Product> {
@Override
public boolean test(Product product) {
return product.getPrice() < 8000;
}
}
這樣實現的話可能有人會說,每次變更需求都需要新建一個實現類,感覺還是有點繁瑣呀,那麼再來優化一下
優化:使用lambda表示式
定義過濾方法:
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
List<Product> prods = new ArrayList<>();
for (Product prod : list){
if (mp.test(prod)){
prods.add(prod);
}
}
return prods;
}
測試方法:
public void test(){
MyPredicate<Product> mp = new PricePredicate();
List<Product> products = filterProductByPredicate(proList, mp);
//列印過濾結果
for (Product pro : products){
System.out.println(pro);
}
}
使用lambda表示式進行過濾,這裡就不需要實現MyPredicate 介面的PricePredicate類了
@Test
public void test(){
List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);
//列印過濾結果
for (Product pro : products){
System.out.println(pro);
}
}
在jdk1.8中還有更加簡便的操作 Stream API
優化四:使用Stream API
甚至不用定義過濾方法,直接在集合上進行操作
// 使用jdk1.8中的Stream API進行集合的操作
@Test
public void test(){
// 根據價格過濾
proList.stream()
.fliter((p) -> p.getPrice() <8000)
.limit(2)
.forEach(System.out::println);
// 根據顏色過濾
proList.stream()
.fliter((p) -> "紅色".equals(p.getColor()))
.forEach(System.out::println);
// 遍歷輸出商品名稱
proList.stream()
.map(Product::getName)
.forEach(System.out::println);
}
Lmabda表示式的語法總結: () -> ();
前置 語法
無引數無返回值 () -> System.out.println(“Hello WOrld”)
有一個引數無返回值 (x) -> System.out.println(x)
有且只有一個引數無返回值 x -> System.out.println(x)
有多個引數,有返回值,有多條lambda體語句 (x,y) -> {System.out.println(“xxx”);return xxxx;};
有多個引數,有返回值,只有一條lambda體語句 (x,y) -> xxxx
口訣:左右遇一省括號,左側推斷型別省
注:當一個介面中存在多個抽象方法時,如果使用lambda表示式,並不能智慧匹配對應的抽象方法,因此引入了函式式介面的概念
什麼是函式式介面?
簡單來說就是隻定義了一個抽象方法的介面(Object類的public方法除外),就是函式式介面,並且還提供了註解:@FunctionalInterface
常見的四大函式式介面
1消費型介面
Consumer 《T》:消費型介面,有參無返回值
@Test
public void test(){
changeStr("hello",(str) -> System.out.println(str));
}
/**
* Consumer<T> 消費型介面
* @param str
* @param con
*/
public void changeStr(String str, Consumer<String> con){
con.accept(str);
}
2供給型介面
- Supplier 《T》:供給型介面,無參有返回值
@Test
public void test2(){
String value = getValue(() -> "hello");
System.out.println(value);
}
/**
* Supplier<T> 供給型介面
* @param sup
* @return
*/
public String getValue(Supplier<String> sup){
return sup.get();
}
3函式式介面
- Function 《T,R》::函式式介面,有參有返回值
@Test
public void test3(){
Long result = changeNum(100L, (x) -> x + 200L);
System.out.println(result);
}
/**
* Function<T,R> 函式式介面
* @param num
* @param fun
* @return
*/
public Long changeNum(Long num, Function<Long, Long> fun){
return fun.apply(num);
}
4斷言型介面
- Predicate《T》: 斷言型介面,有參有返回值,返回值是boolean型別
public void test4(){
boolean result = changeBoolean("hello", (str) -> str.length() > 5);
System.out.println(result);
}
/**
* Predicate<T> 斷言型介面
* @param str
* @param pre
* @return
*/
public boolean changeBoolean(String str, Predicate<String> pre){
return pre.test(str);
}
在四大核心函式式介面基礎上,還提供了諸如BiFunction、BinaryOperation、toIntFunction等擴充套件的函式式介面,都是在這四種函式式介面上擴充套件而來的,不做贅述。
總結:函式式介面的提出是為了讓我們更加方便的使用lambda表示式,不需要自己再手動建立一個函式式介面,直接拿來用就好了,貼
方法引用
若lambda體中的內容有方法已經實現了,那麼可以使用“方法引用”
也可以理解為方法引用是lambda表示式的另外一種表現形式並且其語法比lambda表示式更加簡單