JDK 1.8 Stream Lambda表達式

在jdk1.8中對hashMap等map集合的數據結構優化 hashMap數據結構的優化

原來的hashMap採用的數據結構是哈希表(數組+鏈表),hashMap默認大小是16,一個0-15索引的數組,如何往裏面存儲元素,首先調用元素的hashcode
方法,計算出哈希碼值,經過哈希算法算成數組的索引值,如果對應的索引處沒有元素,直接存放,如果有對象在,那麼比較它們的equals方法比較內容
如果內容一樣,後一個value會將前一個value的值覆蓋,如果不一樣,在1.7的時候,後加的放在前面,形成一個鏈表,形成了碰撞,在某些情況下如果鏈表
無限下去,那麼效率極低,碰撞是避免不了的
加載因子:0.75,數組擴容,達到總容量的75%,就進行擴容,但是無法避免碰撞的情況發生
在1.8之後,在數組+鏈表+紅黑樹來實現hashmap,當碰撞的元素個數大於8時 & 總容量大於64,會有紅黑樹的引入
除了添加之後,效率都比鏈表高,1.8之後鏈表新進元素加到末尾
ConcurrentHashMap (鎖分段機制),concurrentLevel,jdk1.8採用CAS算法(無鎖算法,不再使用鎖分段),數組+鏈表中也引入了紅黑樹的使用

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;
    }
}

優化二:使用匿名內部類

定義過濾方法:

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 test2(){
    filterProductByPredicate(proList, new MyPredicate<Product>() {
        @Override
        public boolean test(Product product) {
            return product.getPrice() < 8000;
        }
    });
}

 // 按顏色過濾
 public void test3(){
     filterProductByPredicate(proList, new MyPredicate<Product>() {
         @Override
         public boolean test(Product product) {
             return "紅色".equals(product.getColor());
         }
     });
 }

優化三:使用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;
    }

使用lambda表達式進行過濾

@Test
public void test4(){
      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表達式,並不能智能匹配對應的抽象方法,因此引入了函數式接口的概念

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章