您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Java中如何實現函數式編程,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
函數式編程是一種結構化編程的范式,主要思想是把運算過程盡量寫成系列嵌套的函數調用。函數編程的概念表述帶有很抽象的感覺,可以基于案例看:
public class Function01 { public static void main(String[] args) { // 運算:(x+y)* c int x1 = 2 ; int y1 = 3 ; int c1 = 4 ; int sum1 = x1 + y1 ; int res1 = sum1 * c1 ; System.out.println("res1 = "+res1); } }
這里基于過程的方式做計算,上面的代碼塊著重在描述程序執行過程。
在看基于函數的方式解決方法:
public class Function02 { public static void main(String[] args) { // 函數式計算 System.out.println("func01 = "+func01(2,3,4)); } private static int func01 (int x,int y,int c){ return (x+y)*c; } }
函數式編程的核心要素:傳入參數,執行邏輯,返回值,也可以沒有返回值。
函數式的編程風格側重描述程序的執行邏輯,不是執行過程。
同上面計算過程相比,函數式編程也減少很多臨時變量的創建,代碼風格也變的簡潔清楚。
在Java語言中有函數式編程風格,但是Java代碼中沒有函數的說法,而是稱為:方法;
public class Function03 { public static void main(String[] args) { Func03 func03 = new Func03(); func03.add(2); System.out.println(func03.res1); } } class Func03 { public int res1 = 0 ; public void add (int a1){ this.res1 = a1 +1 ; } }
類定義引用數據類型,類實例化后的對象可以調用類內部的方法和數據,這是最直觀的感覺。
但是方法又有靜態和非靜態的區別,靜態方法屬于類所有,類實例化前即可使用。
非靜態方法可以訪問類中的任何成員變量和方法,并且必須是類實例化后的對象才可以調用。
Lambda表達式也可稱為閉包,是推動Java8發布的最重要新特性,允許把函數作為一個方法的參數(函數作為參數傳遞進方法中)。
這里就很鮮明的對比Lambda表達式語法和傳統用法。
public class Lambda01 { interface LambdaOpera { int operation(int a, int b); } public static void main(String[] args) { LambdaOpera lambdaOpera = new LambdaOpera(){ @Override public int operation(int a, int b) { return a * b ; } }; System.out.println(lambdaOpera.operation(3,2)); LambdaOpera lambdaOpera01 = (int a, int b) -> a + b; LambdaOpera lambdaOpera02 = (int a, int b) -> a - b; System.out.println(lambdaOpera01.operation(3,2)); System.out.println(lambdaOpera02.operation(3,2)); } }
在看一個直觀的應用案例,基于Lambda的方式創建線程,可以使代碼變的更加簡潔緊湊:
public class Lambda02 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 2; i++) { System.out.println(i); } } }).start(); // 對比 Lambda 方式 new Thread(() -> { for (int i = 0; i < 2; i++) { System.out.println(i); } }).start(); } }
在看一下Runnable接口的結構:
FunctionalInterface標記在接口上,表示該接口是函數式接口,并且該接口只包含一個抽象方法,
@FunctionalInterface public interface Runnable { public abstract void run(); }
Lambda表達式本身可以理解為就是一個接口的實現過程,這里runnable就是完整的Lambda表達式聲明:
public class Lambda04 { public static void main(String[] args) { Runnable runnable = () -> { System.out.println("run one..."); }; Thread thread = new Thread(runnable); thread.start(); } }
Lambda表達式最直觀的作用就是使得代碼變得異常簡潔,并且可以作為參數傳遞。
Lambda表達式雖然有很多優點,但是使用的時候需要定義一些接口用來完成編碼,這樣又使得表達式又變得重量級,Java8自身已經提供幾個常見的函數式接口。
Function:輸入一個參數,返回一個結果;
Consumer:輸入一個參數,不返回結果;
BiFunction:輸入兩個參數,返回一個結果;
BiConsumer:輸入兩個參數,不返回任何結果;
public class Lambda05 { public static void main(String[] args) { Function<Integer, Integer> function01 = x -> x * 2; System.out.println(function01.apply(2)); BiFunction<Integer, Integer, Integer> function02 = (x, y) -> x * y; System.out.println(function02.apply(2, 3)); Consumer<String> consumer01 = msg -> System.out.println("msg:"+msg); consumer01.accept("hello"); BiConsumer<String,Integer> consumer02 = (msg,i) -> System.out.println(msg+":"+i); consumer02.accept("world",3); } }
如果面對更復雜的業務需求,可以自定義函數式接口去解決。
Optional類是Java函數式編程的應用,主要用來解決常見的空指針異常問題。
在Java編程的開發中,很多地方都能常見空指針異常的拋出,如果想避免這個問題就要加入很多判斷:
public class Optional01 { public static void main(String[] args) { User user = new User(1,"hello") ; if (user != null){ if (user.getName() != null){ System.out.println(user.getName()); } } } }
為了確保程序不拋出空指針這種低級的錯誤,在程序中隨處可以null的判斷,代碼顯然冗余和繁雜。
基于Optional類創建的對象可能包含空值和null值,也同樣會拋出對應的異常:
public class Optional02 { public static void main(String[] args) { // NoSuchElementException Optional<User> optionalUser = Optional.empty(); optionalUser.get(); // NullPointerException Optional<User> nullOpt = Optional.of(null); nullOpt.get(); } }
所以在不明確對象的具體情況下,使用ofNullable()方法:
public class Optional03 { public static void main(String[] args) { User user = new User(1,"say"); Optional<User> optionalUser = Optional.ofNullable(user); if (optionalUser.isPresent()){ System.out.println(optionalUser.get().getName()); } User user1 = null ; User createUser = Optional.ofNullable(user1).orElse(createUser()); System.out.println(createUser.getName()); User user2 = null ; Optional.ofNullable(user2).orElseThrow( () -> new RuntimeException());; } public static User createUser (){ return new User(2,"hello") ; } }
這樣看下來Optional結合鏈式方法和Lambda表達式就很大程度上簡化了應用的代碼量:
public class Optional04 { public static void main(String[] args) { // 1、map轉換方法 User user = new User(99, "Java"); // user = null ; String name = Optional.ofNullable(user) .map(u -> u.getName()).orElse("c++"); System.out.println(name); // 2、過濾方法 Optional<User> optUser01 = Optional.ofNullable(user) .filter(u -> u.getName() != null && u.getName().contains("c++")); // NoSuchElementException System.out.println(optUser01.get().getName()); } }
Optional提供null處理的各種方法,可以簡潔很多代碼判斷,但是在使用風格上和之前變化很大。
如果Optional簡化很多Null的判斷,那Stream流的API則簡化了很多集合的遍歷判斷,同樣也是基于函數式編程。
上述為Stream接口繼承關系如圖,同樣提供一些特定接口和較大的包裝接口,通過源碼查看,可以看到和函數編程也是密切相關。
public class Stream01 { public static void main(String[] args) { Stream<String> stream = Stream.of("hello", "java"); stream.forEach(str -> System.out.print(str+";")); } }
Stream與函數接口結合使用,函數接口又可以使用Lambda表達式進行簡化代碼。在Java8通過Stream可以大量簡化集合使用的代碼復雜度。
public class Stream02 { public static void main(String[] args) { // 1、轉換Stream List<String> list = Arrays.asList("java+;", "c++;", "net;"); list.stream(); // 2、forEach操作 list.stream().forEach(System.out::print); // 3、map映射,輸出 3,4 IntStream.rangeClosed(2,3).map(x->x+1).forEach(System.out::println); // 4、filter過濾 list.stream().filter(str -> str.contains("+")).forEach(System.out::print); // 5、distinct去重 Integer[] arr = new Integer[]{3, 1, 3, 1, 2,4}; Stream.of(arr).distinct().forEach(System.out::println); // 6、sorted排序 Stream.of(arr).sorted().forEach(System.out::println); // 7、collect轉換 List<String> newList = list.stream().filter(str -> str.contains("+")) .collect(Collectors.toList()); newList.stream().forEach(System.out::print); } }
在沒有Stream相關API之前,對于集合的操作和遍歷都會產生大量的代碼,通過Stream相關API集合的函數式編程和Lambda表達式的風格,簡化集合很多操作。
上述就是小編為大家分享的Java中如何實現函數式編程了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。