Java8 (1)

參考資料:java

  《Java8 in Action》 Raoul-Gabriel Urmapython

1、jdk8

  客觀的說,Java8是一次有重大演進的版本,甚至不少人認爲java8所作的改變,在許多方面都比Java歷史上任何一次改變都深遠。編程

    Scala,python這樣優秀編程語言中對函數式編程的處理,guava中的理念等等....設計模式

  java8的代碼更簡潔...併發

  java8對併發編程更加友好,java一直努力讓併發編程更爲高效,出錯更少,jdk1.0裏有線程和鎖,Java 5增長的工業模塊,Thread pools和一大堆併發工具類, Java7增長了fork/join框架,Java8則對並行提供了一個新的思路app

  新的API,例如Stream等  框架

  等等編程語言

2、經過行爲參數化傳遞代碼

首先有一個蘋果類ide

   public static class Apple {
        private int weight = 0;
        private String color = "";

        public Apple(int weight, String color){
            this.weight = weight;
            this.color = color;
        }

        public Integer getWeight() {
            return weight;
        }

        public void setWeight(Integer weight) {
            this.weight = weight;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public String toString() {
            return "Apple{" +
                    "color='" + color + '\'' +
                    ", weight=" + weight +
                    '}';
        }
    }

 

1. 需求

  須要2個函數以供過濾出須要的蘋果函數式編程

public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){
        List<Apple> result = new ArrayList<Apple>();
        for(Apple apple: inventory){
            if(apple.getColor().equals(color)){
                result.add(apple);
            }
        }
        return result;
    }

    public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){
        List<Apple> result = new ArrayList<Apple>();
        for(Apple apple: inventory){
            if(apple.getWeight() > weight){
                result.add(apple);
            }
        }
        return result;
    }

上面的代碼比較囉嗦,並且若是還有新的需求,依舊須要添加新的方法,之前的java實現函數就是靜態方法。

2. 第一次改造

Java中封裝行爲的方式只能經過匿名類之類的方式。首先定義一個接口:

interface ApplePredicate{
        public boolean test(Apple a);
 }

因而方法變爲:

public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
        List<Apple> result = new ArrayList<Apple>();
        for(Apple apple : inventory){
            if(p.test(apple)){
                result.add(apple);
            }
        }
        return result;
    }

在以前的java,用以下方式:

static class AppleWeightPredicate implements ApplePredicate{
        public boolean test(Apple apple){
            return apple.getWeight() > 150;
        }
    }
    static class AppleColorPredicate implements ApplePredicate{
        public boolean test(Apple apple){
            return "green".equals(apple.getColor());
        }
    }

2個新的實現類,從設計模式上是策略模式... 能夠更靈活的擴展,可是感受代碼更囉嗦了...

固然你也能夠不定義出類,使用匿名內部類,仍是很囉嗦.

        List<Apple> redApples2 = filter(inventory, new ApplePredicate() {
            public boolean test(Apple a){
                return a.getColor().equals("red");
            }
        });

 

3. 使用Lambda表達式

List<Apple> result = filter(inventory ,(Apple apple)-> "red".equals(apple.getColor()));

jdk8中再進一步將Perdicate抽象爲泛型類...

public interface Predicate<T> {
    boolean test(T var1);
    //....  
}

3、Lambda表達式

3.1 lambda簡介

不少語言都支持lambda,例如python,能夠把lambda表達式簡單理解爲表示可傳遞的匿名函數的一種方式: 它沒有名稱,可是有參數列表、函數主題、返回類型,可能還有一個異常列表.

  • 匿名 - 沒有方法名
  • 函數 - Lambda不屬於任何一個類。
  • 傳遞 - 能夠作爲參數傳遞給方法或者存儲在變量中
  • 簡潔

讓咱們來改造一段代碼...

        Comparator<Apple> byWeight = new Comparator<Apple>() {
            @Override
            public int compare(Apple o1, Apple o2) {
                return o1.getWeight().compareTo(o2.getWeight());
            }
        };

        Comparator<Apple> byWeight2 = (Apple a1, Apple a2) -> a1.getWeight() - a2.getWeight();
   

(Apple a1, Apple a2) 是Lambda的參數列表,加上一個小箭頭,加上主體 a1.getWeight() - a2.getWeight()

 

Lambda的基本語法:

  (params) -> experssion

  (params) -> {statements;}

舉例:

 (1) () -> {};

 (2) () -> "Raoul"

 (3) () -> {return "aaa";}

 (4) (int i) -> return "Al" + 1;

 (5) (String s) -> {"IronMan";}

上述中只有(4), (5) 不符合語法,(4)的主體是statements;須要用{},(5)的主體是statements,所以不能使用{}...

 

3.2 在哪裏可使用Lambda

1. 函數式接口

  函數是接口就是隻定義了一個抽象方法的接口。 jdk8中接口還能夠定義默認方法,哪怕有不少的默認方法,可是隻要接口只定義了一個抽象方法,它就仍然是一個函數式接口。

  Lambda容許你把lambda表達式做爲函數式接口的一個實現的實例

  

     MyInteface myInteface = (int i, int j) -> i+j;
     System.out.println(myInteface.add(1,2));
    

    public  interface MyInteface{
        int add(int i, int j);
    }

 

2. 函數式描述符

 函數式接口中有且只有一個方法,這個方法的簽名就是lambda表達式的簽名。這種抽象方法叫作函數描述符...

@FuntionalInterface?

  接口標註,表示接口會被設計爲一個函數式接口。按照官方說法就是:  

  • The type is an interface type and not an annotation type, enum, or class.
  • The annotated type satisfies the requirements of a functional interface.

 

3.3 使用函數式接口

java.util.function包中引入了經常使用的函數式接口

1. Predicate

    public static <T> List<T> filte(List<T> list, Predicate<T> p){
        List<T> results = new ArrayList<T>();
        for (T t : list) {
            if (p.test(t)) results.add(t);
        }
        return results;
    }

Predicate中還有一些add, not等默認方法,暫不討論...

2. Consumer

其中定義了一個accept()方法,沒有返回值

    public static <T> void forEach(List<T> list, Consumer<T> c){
        for (T i : list) {
            c.accept(i);
        }
    }

    public static void main(String[] args) {
        forEach(
                Arrays.asList(1,2,3,4,5),
                (Integer i) -> {
                    System.out.println(i);
                }
        );
    }

 

3. Function

相似於Guava的Function,定義了一個apply的方法,例子中打印每一個字符串的長度...

    public static <T, R> List<R> map(List<T> list, Function<T, R> f){
        List<R> result = new ArrayList<R>();
        for (T t : list) {
            result.add(f.apply(t));
        }
        return result;
    }

    public static void main(String[] args) {
        List<Integer> l = map(
                Arrays.asList("lambdas","in","action"),
                (String s) -> s.length()
        );
        System.out.println(l);
    }

 

4. IntPredicate

自從jdk1.5以後就支持自動裝箱inbox,但裝箱以後好比將一個原始類型轉換成了Integer,在heap劃分一塊內存分配等等,IntPredicate能夠避免無謂的裝箱..

IntPredicate evenNumbers = (int i) -> i%2 ==1;
 Predicate<Integer> predicate = (Integer i) -> i%2 ==1;

也能夠說由於泛型每每不能使用基本類型

 

3.4 方法引用

方法引用能夠被看作僅僅調用特定Lambda的一種快捷寫法。例如

(Apple a) -> a.getWeight() 能夠寫成 Apple::getWeight

() -> Thread.currentThread.dumpStack() 能夠寫成 Thread.currentThread()::dumpStack

(str, i) -> str.substring(i) 能夠寫成 String:substring

(Sring s) -> System.out.println(s) 能夠寫成 System.out::println

 

如何構建方法引用?

(1) 靜態方法,類的方法,例如Interger的parseInt Interger::parseInt

(2) 實例方法, String::length

(3) 指向現有方法的方法引用: expensiveTransaction::getValue

實例: 排序

使用Lambda表達式的用法

    public static void main(String[] args) {
        Comparator<String> comparator = (String s1,String s2) -> s1.compareToIgnoreCase(s2);
        List<String> l = Arrays.asList("a","b","A","B");
        Collections.sort(l,comparator);
        System.out.println(l);
    }

可換成:

Comparator<String> comparator = String::compareToIgnoreCase;
        List<String> l = Arrays.asList("a","b","A","B");
        Collections.sort(l,comparator);
        System.out.println(l);

構造函數引用...

 

3.5 Lambda表達式複合用法

1. 比較器複合

public static void main(String ... args){
        List<Apple> inventory = new ArrayList<>();
        inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")));
        //1. 使用逆序
        inventory.sort(
                Comparator.comparing(Apple::getWeight).reversed()
        );
        //2. 比較器鏈
        inventory.sort(
                Comparator.comparing(Apple::getWeight).reversed().thenComparing(Apple::getColor)
        );
    }

比較器鏈中若是重量相同,就按顏色排序...

 

2. 謂詞複合

    public static void main(String ... args){
        Predicate<Apple> redApple = (Apple a) -> "red".equals(a.getColor());
        Predicate<Apple> notRedApple = redApple.negate();
        Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight()>150);
        Predicate<Apple> readAndHeavyOrGreenApple = redApple.and(a -> a.getWeight()>150).or(a -> "green".equals(a.getColor()));
    }

 

3. 函數複合

 以Function爲例,實現相似於g(f(x))和f(g(x))的效果

    public static void main(String... args) {
        Function<Integer, Integer> f = x -> x + 1;
        Function<Integer, Integer> g = x -> x * 2;
        Function<Integer, Integer> h = f.andThen(g);
        Function<Integer, Integer> k = f.compose(g);
        System.out.println(h.apply(3));
        System.out.println(k.apply(3));
    }
相關文章
相關標籤/搜索