1. 程式人生 > >java1.8 新特性 - Lambda表示式

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表示式更加簡單