有關JDK8新特性以前寫了三篇博客:html
一、java代碼之美(1)---Java8 Lambdajava
二、java代碼之美(2)---Java8 Streamapp
三、java代碼之美(13)--- Predicate詳解ide
這一篇咱們來了解JDK8已經定義好的幾個函數式接口。函數
Jdk8以後新增的一個重要的包 : java.util.functionui
該包下全部的接口都是函數式接口, 按分類主要分爲四大接口類型: Function
、Consumer
、Predicate
、Supplier
。有關Predicate這裏再也不講解,由於上面有單獨寫過一篇博客。this
延伸以下code
這裏也僅僅是展現一部分,咱們看看java.util.function包下htm
做用
一聽這名字就知道是消費某個對象,沒有返回值。對象
在源碼中只有兩個方法,一個抽象方法,一個默認方法。
@FunctionalInterface public interface Consumer<T> { /** * 抽象方法:傳入一個指定泛型的參數,無返回值 */ void accept(T t); /** * 如同方法名字同樣andThen,相似一種相加的功能(下面會舉例說明) */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
public static void main(String[] args) { testConsumer(); testAndThen(); } /** * 一個簡單的平方計算 */ public static void testConsumer() { //設置好Consumer實現方法 Consumer<Integer> square = x -> System.out.println("平方計算 : " + x * x); //傳入值 square.accept(2); } /** * 定義3個Consumer並按順序進行調用andThen方法 */ public static void testAndThen() { //當前值 Consumer<Integer> consumer1 = x -> System.out.println("當前值 : " + x); //相加 Consumer<Integer> consumer2 = x -> { System.out.println("相加 : " + (x + x)); }; //相乘 Consumer<Integer> consumer3 = x -> System.out.println("相乘 : " + x * x); //andThen拼接 consumer1.andThen(consumer2).andThen(consumer3).accept(1); }
運行結果
單個這樣消費看去並沒啥意義,但若是是集合操做就有意義了,因此Jdk8的Iterator接口就引入了Consumer。
Iterable接口的forEach方法須要傳入Consumer,大部分集合類都實現了該接口,用於返回Iterator對象進行迭代。
public interface Iterable<T> { //forEach方法傳入的就是Consumer default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } }
咱們在看給咱們帶來的便利
public static void main(String[] args) { //假設這裏有個集合,集合裏的對象有個status屬性,如今我想對這個屬性賦值一個固定值 List<Pension> pensionList = new ArrayList<>(); //一、傳統的經過for循環添加 for (Pension pension : pensionList) { pension.setStatus(1); } //二、經過forEach的Consumer添加 pensionList.forEach(x -> x.setStatus(1)); }
這樣一比較是否是代碼簡潔了點,這就是Consumer是咱們代碼帶來簡潔的地方。
做用
提早定義可能返回的一個指定類型結果,等須要調用的時候再獲取結果。
@FunctionalInterface public interface Supplier<T> { /** * 只有這一個抽象類 */ T get(); }
源碼很是簡單。
在JDK8中Optional對象有使用到
Optional.orElseGet(Supplier<? extends T>) //當this對象爲null,就經過傳入supplier建立一個T返回。
咱們看下源碼
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
使用示例
public static void main(String[] args) { Person son = null; //先判斷son是否爲null,若是爲不爲null則返回當前對象,若是爲null則返回新建立的對象 BrandDTO optional = Optional.ofNullable(son).orElseGet(() -> new Person()); }
這樣代碼是否是又簡單了。有關Optional這裏就很少說,接下來會單獨寫一篇博客。
做用
實現一個」一元函數「,即傳入一個值通過函數的計算返回另外一個值。
@FunctionalInterface public interface Function<T, R> { /** * 抽象方法: 根據一個數據類型T加工獲得一個數據類型R */ R apply(T t); /** * 組合函數,調用當前function以前調用 */ default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * 組合函數,調用當前function以後調用 */ default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * 靜態方法,返回與原函數參數一致的結果。x=y */ static <T> java.util.function.Function<T, T> identity() { return t -> t; } }
public static void main(String[] args) { applyTest(); andThenTest(); composeTest(); test(); } /** * 一、apply 示例 */ private static void applyTest() { //示例1:定義一個funciton,實現將String轉換爲Integer Function<String, Integer> function = x -> Integer.parseInt(x); Integer a = function.apply("100"); System.out.println(a.getClass()); // 結果:class java.lang.Integer } /** * 二、andThen 示例 */ private static void andThenTest() { //示例2:使用andThen() 實現一個函數 y=10x + 10; //先執行 10 * x Function<Integer, Integer> function2 = x -> 10 * x; //經過andThen在執行 這裏的x就等於上面的10 * x的值 function2 = function2.andThen(x -> x + 10); System.out.println(function2.apply(2)); //結果:30 } /** * 三、compose 示例 */ private static void composeTest() { //示例3:使用compose() 實現一個函數 y=(10+x)2; Function<Integer, Integer> function3 = x -> x * 2; //先執行 x+10 在執行(x+10)*2順序與上面相反 function3 = function3.compose(x -> x + 10); System.out.println(function3.apply(3)); //結果:26 } /** * 四、綜合示例 */ private static void test() { //示例4:使用使用compose()、andThen()實現一個函數 y=(10+x)*2+10; //執行第二步 Function<Integer, Integer> function4 = x -> x * 2; //執行第一步 function4 = function4.compose(x -> x + 10); //執行第三步 function4 = function4.andThen(x -> x + 10); System.out.println(function4.apply(3)); //結果:36 }
有兩個地方很經常使用
一、V HashMap.computeIfAbsent(K , Function<K, V>) // 簡化代碼,若是指定的鍵還沒有與值關聯或與null關聯,使用函數返回值替換。 二、<R> Stream<R> map(Function<? super T, ? extends R> mapper); // 轉換流
computeIfAbsent使用示例
Map<String, List<String>> map = new HashMap<>(); List<String> list; // java8以前寫法 list = map.get("key"); if (list == null) { list = new LinkedList<>(); map.put("key", list); } list.add("11"); // 使用 computeIfAbsent 能夠這樣寫 若是key返回部位空則返回該集合 ,爲空則建立集合後返回 list = map.computeIfAbsent("key", k -> new ArrayList<>()); list.add("11");
stream中map使用示例
public static void main(String[] args) { List<Person> persionList = new ArrayList<Person>(); persionList.add(new Person(1,"張三","男",38)); persionList.add(new Person(2,"小小","女",2)); persionList.add(new Person(3,"李四","男",65)); //一、只取出該集合中全部姓名組成一個新集合(將Person對象轉爲String對象) List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList()); System.out.println(nameList.toString()); }
代碼是否是又簡潔了。
總結
這些函數式接口做用在我看來,就是定義一個方法,方法中有個參數是函數式接口,這樣的話函數的具體實現則由調用者來實現。這就是函數式接口的意義所在。
通常咱們也會不多去定義一個方法,方法參數包含函數接口。咱們更重要的是學會使用JDk8中帶有函數式接口參數的方法,來簡化咱們的代碼。
一、JDK1.8函數式接口Function、Consumer、Predicate、Supplier
你若是願意有所做爲,就必須善始善終。(25)