Java8 (1)
參考資料:
《Java8 in Action》 Raoul-Gabriel Urma
一、jdk8
客觀的說,Java8是一次有重大演進的版本,甚至很多人認(rèn)為java8所做的改變,在許多方面都比Java歷史上任何一次改變都深遠。
? Scala,python這樣優(yōu)秀編程語言中對函數(shù)式編程的處理,guava中的理念等等....
java8的代碼更簡潔...
java8對并發(fā)編程更加友好,java一直努力讓并發(fā)編程更為高效,出錯更少,jdk1.0里有線程和鎖,Java 5增加的工業(yè)模塊,Thread pools和一大堆并發(fā)工具類, Java7增加了fork/join框架,Java8則對并行提供了一個新的思路
新的API,例如Stream等
等等
二、通過行為參數(shù)化傳遞代碼
首先有一個蘋果類
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個函數(shù)以供過濾出需要的蘋果
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實現(xiàn)函數(shù)就是靜態(tài)方法。
2. 第一次改造
Java中封裝行為的方式只能通過匿名類之類的方式。首先定義一個接口:
interface ApplePredicate{public boolean test(Apple a);}于是方法變?yōu)?
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個新的實現(xiàn)類,從設(shè)計模式上是策略模式... 可以更靈活的擴展,但是感覺代碼更啰嗦了...
當(dāng)然你也可以不定義出類,使用匿名內(nèi)部類,還是很啰嗦.
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);//.... }三、Lambda表達式
3.1 lambda簡介
很多語言都支持lambda,例如python,可以把lambda表達式簡單理解為表示可傳遞的匿名函數(shù)的一種方式: 它沒有名稱,但是有參數(shù)列表、函數(shù)主題、返回類型,可能還有一個異常列表.
- 匿名 - 沒有方法名
- 函數(shù) - Lambda不屬于任何一個類。
- 傳遞 - 可以做為參數(shù)傳遞給方法或者存儲在變量中
- 簡潔
讓我們來改造一段代碼...
Comparator<Apple> byWeight = new Comparator<Apple>() {@Overridepublic 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的參數(shù)列表,加上一個小箭頭,加上主體 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. 函數(shù)式接口
函數(shù)是接口就是只定義了一個抽象方法的接口。 jdk8中接口還可以定義默認(rèn)方法,哪怕有很多的默認(rèn)方法,但是只要接口只定義了一個抽象方法,它就仍然是一個函數(shù)式接口。
Lambda允許你把lambda表達式作為函數(shù)式接口的一個實現(xiàn)的實例
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. 函數(shù)式描述符
?函數(shù)式接口中有且只有一個方法,這個方法的簽名就是lambda表達式的簽名。這種抽象方法叫做函數(shù)描述符...
@FuntionalInterface?
接口標(biāo)注,表示接口會被設(shè)計為一個函數(shù)式接口。按照官方說法就是:
- 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 使用函數(shù)式接口
java.util.function包中引入了常用的函數(shù)式接口
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等默認(rèn)方法,暫不討論...
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,但裝箱之后比如將一個原始類型轉(zhuǎn)換成了Integer,在heap劃分一塊內(nèi)存分配等等,IntPredicate可以避免無謂的裝箱..
IntPredicate evenNumbers = (int i) -> i%2 ==1;Predicate<Integer> predicate = (Integer i) -> i%2 ==1;也可以說因為泛型往往不能使用基本類型
?
3.4 方法引用
方法引用可以被看做僅僅調(diào)用特定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
?
如何構(gòu)建方法引用?
(1) 靜態(tài)方法,類的方法,例如Interger的parseInt Interger::parseInt
(2) 實例方法, String::length
(3) 指向現(xiàn)有方法的方法引用: 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);構(gòu)造函數(shù)引用...
?
3.5 Lambda表達式復(fù)合用法
1. 比較器復(fù)合
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. 謂詞復(fù)合
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. 函數(shù)復(fù)合
?以Function為例,實現(xiàn)類似于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));}?
轉(zhuǎn)載于:https://www.cnblogs.com/carl10086/p/6035731.html
總結(jié)
- 上一篇: 【软件周刊】D语言卷土重来,Vue.js
- 下一篇: Java读取word文件,字体,颜色