因爲項目中用到了比較多有關於 Java8 中新的東西,一開始本身只是會寫,可是寫起來不太順,而後就在網上找到了一個很好的關於Java8新特性的視頻,因此就進行了學習了一下,如下是本身對 lambda 表達式和 Stream API 的筆記和相應的理解。 視頻地址,有興趣的能夠自行觀看。java
在說 Lambda 以前,首先要說的是函數式接口。這個能夠說是爲了 Lambda 表達式而存在的一個東西。那麼什麼是函數式接口?api
定義: 接口中只有一個抽象接口。
像 java.util.function 下的全部接口都是函數式接口。Java1.8提供@FunctionalInterface檢測一個接口是不是一個函數式接口。
eg: java.util.function 包下的 Consumer 接口代碼數組
@FunctionalInterface public interface Consumer<T> { void accept(T t); // jdk 1.8 接口能夠有默認實現 default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
瞭解了什麼是函數式接口後,lambda 表達式就很好理解了。數據結構
"->" 是 lambda 表達式的符號 左側表示函數式接口中抽象方法的參數列表,右側表示你對這個方法的實現。
舉個例子eg:app
public class Test{ public static void main(String[] args){ Consumer consumer = x-> System.out.println(x); consumer.accept(1); } }
輸出 1;ide
咱們通常對函數式接口的使用的時候,都會對其進行封裝。函數
Consumer
eg:
/** * @ClassName ConsumerTest * @Description 消費型接口, 消費字符串字段 打印輸出 * @Author ouyangkang * @Date 2019-02-18 15:46 **/ public class ConsumerTest { public static void main(String[] args) { test("hello",x-> System.out.println(x)); } public static <T> void test(T t, Consumer<T> consumer) { consumer.accept(t); } }
輸出:hello
若是須要多個參數列表的話,也能夠在 java.util.function 包下找到相應的函數式接口 好比 ObjLongConsumer。其餘的能夠自行查看學習
Supplier
/** * @ClassName SupplerTest * @Description 供給型接口 字符串拼接 * @Author ouyangkang * @Date 2019-02-18 15:53 **/ public class SupplerTest { public static void main(String[] args) { String hello = test("hello ", () -> "word!"); System.out.println(hello); } public static String test(String str,Supplier<String> supplier){ return str + supplier.get(); } }
輸出爲:hello word!
若是須要返回得數據爲基本數據類型,能夠在 java.util.function 包下找到相應的函數式接口 好比:getAsLong 其餘的能夠自行查看
Function<T, R> 只有一個抽象方法名爲 apply,參數列表只有一個參數爲T,有返回值,返回值的數據類型爲R。
/** * @ClassName FunctionTest * @Description 函數式接口 將字符串轉換成大寫的 * @Author ouyangkang * @Date 2019-02-18 16:01 **/ public class FunctionTest { public static void main(String[] args) { String test = test("hello", x -> x.toUpperCase()); System.out.println(test); } public static String test(String str , Function<String,String> function){ return function.apply(str); } }
輸出爲:HELLO
若是須要多個入參,而後又返回值的話,能夠在 java.util.function 包下找到相應的函數式接口 好比 BiFunction。其餘的能夠自行查看
斷言型又名判斷型。 Predicate
/** * @ClassName PredicateTest * @Description 斷言型接口,判斷字符串大小是否大於6 * @Author ouyangkang * @Date 2019-02-18 16:16 **/ public class PredicateTest { public static void main(String[] args) { boolean hello = test("hello", x -> x.length() > 6); System.out.println(hello); } public static boolean test(String str, Predicate<String> predicate){ return predicate.test(str); } }
輸出爲: false
Stream 做爲 Java 8 的一大亮點,它與 java.io 包裏的 InputStream 和 OutputStream 是徹底不一樣的概念。Stream中間操做,多箇中間操做能夠鏈接起來造成一個流水線,除非流水線上觸發了終止操做,不然中間不會執行任何處理!而終止操做時會一次性所有處理,稱爲惰性處理。要進行流操做首先要獲取流。有4中方法能夠獲取流。
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); // 經常使用獲取流的方式 Stream<Integer> stream = list.stream(); }
public static void main(String[] args) { int[] a = new int[]{1,2,3,4}; IntStream stream = Arrays.stream(a); }
public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3); }
public static void main(String[] args) { Stream<Integer> iterate = Stream.iterate(0, x -> x + 2); }
全部的對流的操做能夠分爲4種,分別爲篩選與分片,映射,排序,終結(歸約,收集)
操做有filter,distant,limit,skip。
filter : 過濾操做,方法參數爲斷言型接口
eg:
public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3); stream.filter(x->x != 2).forEach(x-> System.out.println(x)); }
輸出:
text 1 3
distinct : 去重操做,方法無參數
limit : 獲取前幾條數據,方法參數爲long
skip : 跳過前多少條數據,而後獲取後面全部的。 方法參數爲long
經常使用操做有 map ,flatMap。
map: 對原數據進行處理,並返回處理後的數據。 方法參數爲函數型接口。
eg:
public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3); stream.map(x->x*2).forEach(System.out::println); }
輸出:
2 4 6
flatMap : 使原來流種的原有數據一個一個整合在另外一個流中。方法參數爲函數型接口,可是返回值爲流。
eg:
public static void main(String[] args) { List<String> list = Arrays.asList("a", "b", "c"); List<String> list2 = Arrays.asList("f","d"); list.stream().flatMap(x->list2.stream().map(y-> x + y)).forEach(System.out::println); }
經常使用操做有sort天然排序,合sort參數爲排序器的定製排序
天然排序eg:
public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3); stream.sorted().forEach(System.out::println); }
輸出:
1 2 3
定製排序
public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3); stream.sorted((x,y)->-Integer.compare(x,y)).forEach(System.out::println); }
輸出:
3 2 1
reduce : 歸約 -- 能夠將流中的元素反覆結合起來,獲得一個值。
eg:
public static void main(String[] args) { List<Integer> list1 = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer reduce = list1.stream().reduce(11, (x, y) -> x + y); System.out.println(reduce); }
輸出 : 66
這個是很是經常使用的一個操做。 將流裝換爲其餘形式。接收到一個Collector接口的實現,用於給Stream中的元素彙總的方法。用collect方法進行收集。方法參數爲Collector。Collector能夠由Collectors中的toList(),toSet(),toMap(Function(T,R) key,Function(T,R) value)等靜態方法實現。
User類
@Data @ToString public class User { private String name; private Integer age; private Integer salary; }
public static void main(String[] args) { List<User> users = Arrays.asList(new User("張三", 19, 1000), new User("張三", 58, 2000), new User("李四", 38, 3000), new User("趙五", 48, 4000) ); List<String> collect = users.stream().map(x -> x.getName()).collect(Collectors.toList()); Set<String> collect1 = users.stream().map(x -> x.getName()).collect(Collectors.toSet()); Map<Integer, String> collect2 = users.stream().collect(Collectors.toMap(x -> x.getAge(), x -> x.getName())); System.out.println(collect); System.out.println(collect1); System.out.println(collect2); }
輸出:
[張三, 張三, 李四, 趙五] [李四, 張三, 趙五] {48=趙五, 19=張三, 38=李四, 58=張三}
Collectors.groupingBy()方法是 返回 Collector 「由基團」上的類型的輸入元件操做實現 T ,根據分類功能分組元素。這個是很是經常使用的操做。
好比你要對名字相同的進行分組。
groupingBy(Function<? super T,? extends K> classifier)
eg:
public static void main(String[] args) { List<User> users = Arrays.asList(new User("張三", 19, 1000), new User("張三", 58, 2000), new User("李四", 38, 3000), new User("趙五", 48, 4000) ); Map<String, List<User>> collect3 = users.stream().collect(Collectors.groupingBy(x -> x.getName())); System.out.println(collect3); }
輸出:{李四=[User{name='李四', age=38, salary=3000}], 張三=[User{name='張三', age=19, salary=1000}, User{name='張三', age=58, salary=2000}], 趙五=[User{name='趙五', age=48, salary=4000}]}
固然還有其餘的一些比較複雜的分組操做,實際代碼看業務來進行實現。
java8中的lambda表達式可能一開始用的時候還不是很熟悉,可是隻要熟悉了,你會發現很是的好用,並且lambda表達式結合stream API能夠進行編寫本身的工具類。在日常項目中能夠很是的省時間,提升寫代碼的效率。我如今給出一個List轉Map的工具類。
public class CollectionStream { public static void main(String[] args) { List<User> users = Arrays.asList(new User("張三", 19, 1000), new User("張三", 58, 2000), new User("李四", 38, 3000), new User("趙五", 48, 4000) ); Map<Integer, Integer> map = listToMap(users, x -> x.getAge(), x -> x.getSalary()); System.out.println(map); } /** * @Author ouyangkang * @Description list 轉map key不能相同 ,若是相同會報錯。 方法對 源數據,key,value過濾null。 * @Date 9:27 2019/2/19 * @param source 源數據 * @param key * @param value * @return java.util.Map<K,V> **/ public static <DTO, K, V> Map<K, V> listToMap(List<DTO> source, Function<? super DTO, ? extends K> key, Function<? super DTO, ? extends V> value) { Objects.requireNonNull(source, "source not null"); Objects.requireNonNull(key, "key not null"); Objects.requireNonNull(value, "value not null"); Map<K, V> map = source.stream() .filter(dto -> dto != null) .filter(dto -> key.apply(dto) != null) .filter(dto -> value.apply(dto) != null) .collect(Collectors.toMap(key, value)); return map; } }