大概一年多以前,我對java8的理解還僅限一些隻言片語的文章之上,後來出於對函數式編程的興趣,買了本參考書看了一遍,而後放在了書架上,後來,當我接手大客戶應用的開發工做以後,java8的一些工具,對個人效率有了不小的提高,所以想記錄一下java'8的一些經常使用場景,我但願這會成爲一個小字典,能讓我免於頻繁翻書,可是總能找到本身想找的知識。java
用於舉例的model:編程
@Data public class Apple { private Long appleId; private String appleName; private Float appleWeight; private Integer appleClassic; }
這無疑是最經常使用的功能之一,其實lambda表達式的做用,應該就是簡潔明瞭,其實是用最短的字符,經過類型推導,語法糖等方式去對編譯器描述清楚這段代碼的功能,這和泛型有點類似,對於編程人員來講,必定程度上也提升了編程效率和代碼可讀性。安全
如經常使用的lambda表達式:
process(()->System.out.println("this is so cool!"))多線程
例如對蘋果重量排序:app
List<Apple> apples = Lists.newArrayList(); for (int i = 1; i < 10; i++) { Apple apple = new Apple(); apples.add(apple); } apples.sort(Comparator.comparing(Apple::getAppleWeight)); 反序: apples.sort(Comparator.comparing(Apple::getAppleWeight).reversed()); 重量相同時:比較等級: apples.sort(Comparator .comparing(Apple::getAppleWeight) .reversed() 謂詞複合查詢: Predicate<Apple> a = apple -> apple.getAppleWeight() > 10; weight10.or(apple -> apple.getAppleClassic() > 2) .and(apple -> StringUtils.equalsIgnoreCase(apple.getAppleName(), "優質蘋果")); 能夠看作(a||b)&&c 函數複合: Function<Apple, Float> f = a -> a.getAppleWeight() + 1; Function<Float, Float> g = a -> a * 2; Function<Apple, Float> h = f.andThen(g); 數學寫做 h=g(f(x)) Function<Apple, Float> g = a -> a.getAppleWeight() + 1; Function<Float, Float> f = a -> a * 2; Function<Apple, Float> h = f.compose(g); 數學寫做 h=f(g(x))
小結:java8實際上想傳遞函數,函數是什麼?是一個映射,能夠看作x->y,輸入x而後映射到值y的過程,
java沒法擺脫一切皆是對象的思想,所以函數式依附在對象上傳遞的,所以也有了下面的說法,方法引用,以及函數式接口,讓函數隨着對象傳遞,爲了函數式編程,甚至專門寫一個接口---對象來傳遞函數。然而,函數纔是主角。函數式編程
方法引用十分簡單,其實也是將方法做爲參數傳遞。使用::域做用符,將一段方法傳遞。
舉例:Apple::getAppleId函數
String::subString System.out::println
利用java進行函數式編程主要就是利用函數式接口,可是函數式接口在java8以前就有一些了,就例如多線程的runnable,可是8之前是沒有lambda表達式的,因此只能使用匿名內部類,在用過lambda表達式的人看來,那是至關臃腫的,8更新了lambda表達式,這就使函數式編程更上一層樓.工具
java8的函數式接口爲咱們傳遞函數提供了工具,咱們能夠本身定義函數式接口,而後讓其餘人,或者是java API調用。
關於函數接口,須要記住的就是兩件事:
函數接口是行爲的抽象;
函數接口是數據轉換器。this
在我接觸到java8流式處理的時候,個人第一感受是流式處理讓集合操做變得簡潔了許多,一般咱們須要多行代碼才能完成的操做,藉助於流式處理能夠在一行中實現。其本質是,將一些本來開發者須要作的處理如迭代等,放在了java庫裏,讓咱們只關心本身的業務邏輯,好比咱們但願對一個包含整數的集合中篩選出全部的偶數,並將其封裝成爲一個新的List返回,那麼在java8以前,咱們須要經過以下代碼實現:線程
過去: List<Integer> evens = new ArrayList<>(); for (final Integer num : nums) { if (num % 2 == 0) { evens.add(num); } } stream實現: List<Integer> evens = nums.stream().filter(num -> num % 2 == 0).collect(Collectors.toList()); 咱們須要取出10個等級高於3的蘋果,跳過其中兩個,按重量排序,去重,而後取出蘋果的Name,而後取出名字的每一個字符: List<String> appleName = apples.parallelStream() .filter(a -> a.getAppleClassic() < 2) .sorted(Comparator.comparing(Apple::getAppleWeight)) .map(Apple::getAppleName) .map(s -> s.split("")) .limit(10) .skip(2) .distinct() .flatMap(Arrays::stream) .collect(Collectors.toList()); 構造AppleId ApppleName Map: Map<Long, String> appleIdMap = apples.stream() .collect(Collectors.toMap(Apple::getAppleId, Apple::getAppleName, (s, s2) -> s.length() > s2.length() ? s : s2)); 謂詞查找: if (appleName.stream().anyMatch(a -> StringUtils.equalsIgnoreCase(a, "一級蘋果"))); if (appleName.stream().allMatch(a -> StringUtils.equalsIgnoreCase(a, "一級蘋果"))); if (appleName.stream().noneMatch(a -> StringUtils.equalsIgnoreCase(a, "一級蘋果"))); 短路查找: appleName.stream() .filter(a -> StringUtils.equalsIgnoreCase(a, "一級蘋果")) .findAny() .ifPresent(System.out::println); findfirst在並行時限制多一些,若是不在乎返回的是哪一個元素,使用findAny。 求和: apples.stream() .map(Apple::getAppleWeight) .reduce(0F, (a, b) -> a + b); 計數: apples.stream().count();
使用stream的好處:
1.更簡潔,更易讀
2.可複合,更靈活
3.可並行
Optional着重爲解決java的NPE問題是Java8提供的爲了解決null安全問題的一個API。善用Optional可使咱們代碼中不少繁瑣、醜陋的設計變得十分優雅。
使用Optional,咱們就能夠把下面這樣的代碼進行改寫: public static String getName(User u) { if (u == null) return "Unknown"; return u.name; } 不過,千萬不要改寫成這副樣子。 public static String getName(User u) { Optional<User> user = Optional.ofNullable(u); if (!user.isPresent()) return "Unknown"; return user.get().name; } 這樣纔是正確使用Optional的姿式。那麼按照這種思路,咱們能夠安心的進行鏈式調用,而不是一層層判斷了。 public static String getName(User u) { return Optional.ofNullable(u) .map(user->user.name) .orElse("Unknown"); } 看一段代碼: public static String getChampionName(Competition comp) throws IllegalArgumentException { if (comp != null) { CompResult result = comp.getResult(); if (result != null) { User champion = result.getChampion(); if (champion != null) { return champion.getName(); } } } throw new IllegalArgumentException("The value of param comp isn't available."); } 讓咱們看看通過Optional加持事後,這些代碼會變成什麼樣子。 public static String getChampionName(Competition comp) throws IllegalArgumentException { return Optional.ofNullable(comp) .map(c->c.getResult()) .map(r->r.getChampion()) .map(u->u.getName()) .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available.")); } 還有不少不錯的使用姿式,好比爲空則不打印能夠這麼寫: string.ifPresent(System.out::println);
參考資料:《Java 8 in Action: Lambdas, streams, and functional-style programming》 Raoul-gabriel Urma (做者), Mario Fusco (做者), Alan Mycroft (做者)
做者:文爍
點擊 閱讀更多 查看更多詳情