日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA高级(一)——lambda

發布時間:2024/3/12 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA高级(一)——lambda 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JAVA高級(一)——lambda

    • lambda基礎
      • 1、是什么是函數是接口?
      • 2、lambda的特點
      • 3、在哪里以及如何使用Lambda
    • lambda實現:環繞執行模式
      • 1、行為參數化
      • 2、使用函數時接口傳遞行為
      • 3、執行一個行為并轉為lambda
    • 使用函數式接口
      • 1、常用的函數型接口
      • 2、重構使用lambda的問題
        • 2.1 重構lambda找不到情況
        • 2.2 從lambda表達式到方法引用的轉換
      • 3、使用lambda重構設計模式
        • 3.1 重構策略模式
        • 3.2 模板方法

lambda基礎

1、是什么是函數是接口?

函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。

? 上圖就是一個函數是接口樣式;

2、lambda的特點

  • 匿名————沒有明確的名稱:寫的少想的多(就是不直觀);
  • 函數————它不像普通的方法有特定的類。但是方法一樣,lambda有方法一切的特性;
  • 傳遞————lambda表達式可以作為參數傳遞給方法或者存儲在變量中;
  • 簡潔————無需使用匿名類,可以省掉很多模板;

下面是一個使用了lambda簡化的代碼模板:

public void test03(){// 原來Consumer<Person> consumer = new Consumer<Person>() {@Overridepublic void accept(Person person) {System.out.println(person);}};// now 1Consumer<Person> consumer1 = person -> System.out.println(person);// now 2Consumer<Person> consumer2 = System.out::println;}

3、在哪里以及如何使用Lambda

當接口是函數式接口時,可以使用;


lambda實現:環繞執行模式

這里我將述說如何自定義一個template去實現我們自己想要的函數格式;

代碼樣例:

// 這一行代碼只能閱讀固定的文件public String BufferReadProcessor1() throws IOException {try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){return br.readLine();}}

1、行為參數化

如果我一次性想讀取多個行文件呢?

String result = processFile((BufferedReader br) -> br.readLine() + br.readLine());

2、使用函數時接口傳遞行為

package com.xiao.java_base.lambdas.demo01;import java.io.BufferedReader; import java.io.IOException;@FunctionalInterface public interface BufferReaderProcessor {String process(BufferedReader bufferedReader) throws IOException; }

現在就可以把這個接口作為新的ProcessFile方法參數了

3、執行一個行為并轉為lambda

@Test public void test01() throws IOException {BufferReaderProcessor bufferReaderProcessor = new BufferReaderProcessor() {@Overridepublic String process(BufferedReader bufferedReader) throws IOException {return bufferedReader.readLine() + bufferedReader.readLine();}};// 使用lambda進行優化BufferReaderProcessor bufferReaderProcessor = bufferedReader ->bufferedReader.readLine() + bufferedReader.readLine();// 執行process進行調用bufferReaderProcessor.process(new BufferedReader(new FileReader("data.txt"))); }

這里就說明了如果創建函數是接口、使用、合并的過程;


使用函數式接口

1、常用的函數型接口

Predicate:里面有一個 test() 方法,設置 Predicate函數接口的實現方法,通過傳遞參數,讓其進行判斷是否符合函數方法中的實現方法,如果符合就獲取,否者就不進行操作;

public static <T> List<T> filter(List<T> list, Predicate<T> p) {List<T> results = new ArrayList<>();for (T t : list) {if (p.test(t)) {results.add(t);}}return results; }public static void main(String[] args) {Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();List<String> eeqwer = filter(Arrays.asList("args","123"), nonEmptyStringPredicate);System.out.println(eeqwer); }

Function:創造型函數式接口

public class FunctionS<T, R> {public static <T, R> List<R> map(List<T> list, Function<T, R> f) {ArrayList<R> result = new ArrayList<>();for (T t : list) {result.add(f.apply(t));}return result;}public static void main(String[] args) {List<Integer> map = map(Arrays.asList("lambda", "in", "action"), String::length);// 傳統寫法//List<Integer> map = map(Arrays.asList("lambda", "in", "action"), new Function<String, Integer>() {// @Override// public Integer apply(String s) {// return s.length();// }//});System.out.println(map);} }

Consume:消費型函數式接口,傳入的數據源在接口中被消費,沒有返回值;

public class ConsumeS<T> {public static <T> void consumes(List<T> list, Consumer<T> consumer){for (T t : list) {consumer.accept(t);}}public static void main(String[] args) {consumes(Arrays.asList("args","123","eeeeer"),System.out::println);}/*運行結果:args123eeeeer*/}

注意:我們還需要考慮一個問題,就是基本數據類型的裝箱拆箱功能,這些會極大的影響java的運行效率

所以java8 就自帶了一個專門不用拆箱和裝箱的類:

比如: IntPredicateDoublePredicate。。。

? 一般來說,針對專門的輸入參數類型的函數式接口的名稱都要加上對應的數據類型,那么就是可以免于上述性能問題;

這里是int數據類型 ?

這里是double基本數據類型 ?

2、重構使用lambda的問題

2.1 重構lambda找不到情況

接下來這個代碼使用lambda的情況下都是可以成立,但是這個到底需要找那個呢?

public static void doSomething(Runnable runnable){runnable.run();}public static <T>void doSomething(Task<T> t){t.execute();}public static void main(String[] args) {// 這個沒問題doSomething(new Task<Object>() {@Overridepublic void execute() {System.out.println("SUCCESS!");}});// 查看錯誤doSomething(() -> System.out.println("AAA"));}

此時IDEA給出了編譯報錯的問題,所以我們不必擔心;但是如何解決這個問題呢?

可以對Task嘗試使用顯式的類型轉換來解決這種模棱兩可的情況:

2.2 從lambda表達式到方法引用的轉換

Lambda表達式非常適用于需要傳遞代碼片段的場景。不過,為了改善代碼的可讀性,也請盡量使用方法引用。因為方法名往往能更直觀地表達代碼的意圖。

Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =menu.stream().collect(groupingBy(dish -> {if (dish.getCalories() <= 400) return CaloricLevel.DIET;else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;else return CaloricLevel.FAT;}));

那么我們可以將 lambda 表達式中的信息進行抽離,直接使用下面這種方式:

// src/com/xiao/java_base/lambdas/demo03 List<Dish> dishes = Arrays.asList(new Dish("土豆片", null, 200),new Dish("油炸土豆", null, 500),new Dish("油油炸土豆片", null, 800),new Dish("油油油炸土豆片", null, 1000));Map<CaloricLevel, List<Dish>> collect =dishes.stream().collect(groupingBy(Dish::getCaloricLevel));collect.forEach((caloricLevel,list) ->{System.out.println("-------------------"+caloricLevel.name()+"-------------------");list.forEach(System.out::print);System.out.println("---------------------------------------------------------");});

但是同時需要修改 Dish 中的 getCaloricLevel 方法

public CaloricLevel getCaloricLevel() {if (this.getCalories() <= 400) return CaloricLevel.DIET;else if (this.getCalories() <= 700) return CaloricLevel.NORMAL;else return CaloricLevel.FAT; }

所以現在思路就很明確了:

? lambda表達式直接通過方法引用的方式獲取到對應的能量等級枚舉值。

看一下獲取的分組值:

3、使用lambda重構設計模式

3.1 重構策略模式

什么是策略模式呢?

一個代表某個算法的接口(Strategy接口)。
一個或多個該接口的具體實現,它們代表了算法的多種實現(比如,實體類ConcreteStrategyA或者ConcreteStrategyB)。
一個或多個使用策略對象的客戶。

假設你希望驗證輸入的內容是否根據標準進行了恰當的格式化(比如只包含小寫字母或數字)。你可以從定義一個驗證文本(以String的形式表示)的接口入手:

public interface ValidationStrategy {boolean execute(String s); }

其次,你定義了該接口的一個或多個具體實現:

public class IsAllLowerCase implements ValidationStrategy {public boolean execute(String s){return s.matches("[a-z]+");} } public class IsNumeric implements ValidationStrategy {public boolean execute(String s){return s.matches("\\d+");} }

之后,你就可以在你的程序中使用這些略有差異的驗證策略了:

public class Validator{private final ValidationStrategy strategy;public Validator(ValidationStrategy v){this.strategy = v;}public boolean validate(String s){return strategy.execute(s);} } Validator numericValidator = new Validator(new IsNumeric()); boolean b1 = numericValidator.validate("aaaa");---- 返回false Validator lowerCaseValidator = new Validator(new IsAllLowerCase ()); boolean b2 = lowerCaseValidator.validate("bbbb");---- 返回true

使用lambda優化的方式:

  • 創建函數式接口:
  • public interface Validator {public boolean validate(String t); }
  • 創建函數方法模板
  • public static boolean validate(String s,Validator validator){return validator.validate(s); }
  • 調用方法
  • boolean bo1 = validate("aaa", s-> s.matches("[a-z]+")); System.out.println(bo1); boolean bo2 = validate("bbb", s-> s.matches("\\\\d+")); System.out.println(bo2);

    3.2 模板方法

    就如同下面代碼,雖然說是策略模式但是,也是屬于lambda的模板方法

    如下業務場景:

    需要編寫一個簡單的在線銀行應用。通常,用戶需要輸入一個用戶賬戶,之后應用才能從銀行的數據庫中得到用戶的詳細信息,最終完成一些讓用戶滿意的操作。不同分行的在線銀行應用讓客戶滿意的方式可能略有不同,比如給客戶的賬戶發放紅利,或者僅僅是少發送一些推廣文件。

    abstract class OnlineBanking {public void processCustomer(int id){Customer c = Database.getCustomerWithId(id);makeCustomerHappy(c);}abstract void makeCustomerHappy(Customer c); }

    這里只是一個代碼樣式,其思想是和銀行代碼一樣的。

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0szli7P0-1637059492930)(E:/typora%E7%AC%94%E8%AE%B0/typoraImg/image-20211115220437927-16369855413413.png)]

    public static void main(String[] args) {boolean bo1 = validate("aaa", s-> s.matches("[a-z]+"));System.out.println(bo1);boolean bo2 = validate("bbb", s-> s.matches("\\\\d+"));System.out.println(bo2); }

    此時如果有其他銀行要使用這個模板,就需要繼承這個類,實現OnlineBanking這個類,但是改用lambda表達式就可以使用下面這個模板。

    public void processCustomer(int id, Consumer<Customer> makeCustomerHappy){Customer c = Database.getCustomerWithId(id);makeCustomerHappy.accept(c); }

    現在,你可以很方便地通過傳遞Lambda表達式,直接插入不同的行為,

    new OnlineBankingLambda().processCustomer(1337, (Customer c) ->System.out.println("Hello " + c.getName());

    總結

    以上是生活随笔為你收集整理的JAVA高级(一)——lambda的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。