介面和lambda表達式筆記

来源:https://www.cnblogs.com/leaveMeAlone/archive/2018/04/08/8747849.html
-Advertisement-
Play Games

涉及到介面的方法和幾種特殊的介面,lambda表達式的作用、目的,以及使用過程中需要註意的一些地方 ...


介面
介面是雙方,即服務提供方和想讓它們的對象對服務是可用的那些類,之間約定的一種機制。
聲明一個介面
public interface IntSequence{ //不提供實現,則該方法為抽象方法,且預設為公有方法,不必為hasNext和next聲明為public
boolean hasNext();
int next();
}
實現介面
public class SquareSequence implements IntSequence{//implements 指示SquareSequence類想要遵從 IntSequence 介面
private int i;

public boolean hasNext(){//實現類必須將介面方法聲明為public,因為預設情況下,它們在包級別可訪問
return true;
}

public int next(){
i++;
return i*i;
}
}
//返回無窮多個平方元素,並且一個對象可以一次一個的處理所有的平方元素

SquareSequence s = new SquareSequence();
double avg = avgrage(s,100);

另外一個IntSequence的實現DigitSequence
public class DigitSequence implements IntSequence{

private int number;

public DigitSequence(int n){
number = n;
}

@Override
public boolean hasNext() {
return number!=0;
}

@Override
public int next() {
int result = number%10;
number = number/10;
return result;
}

public int rest(){
return number;
}
}
當子類型T的任何值不需要轉換就能賦值給父類型S的變數時,類型S是類型T(子類)的父類,例如,IntSequence 介面是DigitSequence類的父類。
雖然聲明介面類型的變數是可能的,但是永遠不會存在類型為介面的對象。所有對象都是類的實例。
IntSequence digits = new DigitSequence(9876);
System.out.println(average.average(digits,100));

從父類轉換為子類,即當知道父類型IntSequence存儲的就是子類型DigitSequence對象時。
IntSequence s = ...;
DigitSequence digits = (DigitSequence) s;
System.out.println(digits.rest());
這種情況下轉換是必須的因為rest方法為digitSequence所特有的。
當然最好在強制轉換前使用instantof來避免轉換異常。
if(s instantof DigitSequence){
DigitSequence digits = (DigitSequence) s;
...
}

繼承介面
public interface Closeable{
void close();
}
public interface Channel extends Closeable{
boolean isOpen();
}
即若想實現channel介面需要提供兩個方法。

實現多個介面,可以在implements後面添加多個介面。

常量
定義在介面內的任何變數自動為 public static final

靜態方法和預設方法(均在java1.8後可以實現)
public interface IntSequence {

public int next();

public static IntSequence digitsOf(int n){ //靜態方法
return new DigitSequence(n);
}

default boolean hasNext(){ //預設方法
return true;
}

解決預設方法衝突
public interface Identified {
default int getID(){return Math.abs(hashCode());}
}
public interface Person {
String getName();
default int getID(){return 0;}
}
public class Employee implements Identified,Person{
@Override
public String getName() {
return null;
}

@Override
public int getID() {
return Person.super.getID();//使用super關鍵字,可以調用父類型的方法。
}

lambda表達式(匿名函數,沒有函數名稱的函數)
用處:增強可讀性,並且使代碼更加簡潔
同時當編譯器可以推斷出變數類型時,可以省略()內的變數類型,且無需為lambda表達式指定返回類型
Runnable task1 = new Runnable() {
@Override
public void run() {
System.out.println("not Lambda");
}
};

Runnable task2 = ()->{System.out.println("Lambda");};

對於Arrays.sort方法,該方法的第二個參數要求是一個comparator介面。
Arrays.sort(strings,(x,y)->x.compareToIgnoreCase(y));
Arrays.sort(strings,String::compareToIgnoreCase);//方法引用,與上式等同
對於類似於 操作符::將方法名稱與類或對象名稱分隔開有以下三種形式
1. 類::實例方法 比如:String::compareToIgnoreCase 與(x,y)->x.compareToIgnoreCase(y)
2. 類::靜態方法 比如:Object::isNull 與x->Object.isNull(x)
3. 對象::實例方法 比如:System.out:;println 與System.out.println(x)
構造函數引用於方法引用類似,區別在於引用的方法名稱都是new 比如 Employee::new

使用lambda表達式的目的
1.實現延遲執行 (在另一個單獨線程中運行代碼、多次運行、恰當時刻運行(排序中比較操作的執行))
多次執行
public static void repeat(int n,Runnable r){
for (int i=0;i<n;i++)r.run();
}

repeat(2,()->System.out.println("ll"));

帶有參數的lambda表達式使用
public static void repeat(int n,IntConsumer r){
for (int i=0;i<n;i++)r.accept(i);
}

public interface IntConsumer{
void accept(int value);
}

repeat(10,i->System.out.println("Countdown:"+(9-i)));
2.選擇函數式介面
大多數編程語言的函數類型都是結構化的。比如為了將兩個字元串映射到一個整數的函數。需要使用類似Function<String,String,Integer>或者(String,String)->int
常用函數式介面
函數式介面 參數類型 返回類型 抽象方法名稱 描述 其他方法
Runnable none void run 執行一個沒有參數或返回值的操作
Supplier<T> none T get 提供類型為T的值
Consumer<T> T void accept 處理T類型的值
BiConsumer<T,U> T,U void accept 處理T類型和U類型的值
Function<T,R> T R apply 參數類型為T的函數
BiFunction<T,U,R> T,U R apply 參數列行為T,U的函數
UnaryOperator<T> T T apply 對類型T進行一元操作
BinaryOperator<T> T,T T apply 對類型T進行二元操作
Predicate<T> T boolean test 布爾值函數
BiPredicate<T,U> T,U boolean test 帶有兩個參數的布爾值函數
3.實現自己的函數式介面
@FunctionalInterface //註釋標記函數式介面
public interface PixelFunction{ //實現(int,int)-> color
Color apply(int x,int y);
}

lambda表達式的作用域
lambda表達式的方法體與嵌套代碼塊有著相同的作用域,因此,也適用同樣的命名衝突和屏蔽規則。在lambda表達式中不允許聲明一個與局部變數同名的參數或局部變數
int f;
Comparator<String> comparator = (f,s)->f.length()-s.length(); //f與上面的int f重名。

訪問來自閉包作用域的變數
public static void repeat(String msg ,int count){
Runnable r = ()->{
for (int i =0;i<count;i++){//將lambda表達式轉變為帶有一個方法的對象,這樣自由變數的值就可以複製到帶對象的實例變數中
System.out.println(msg);
}
};
new Thread(r).start();
}
lambda表達式有三個部分: 1.代碼塊 2.參數 3.自由變數的值(既不是參數變數也不是代碼內部定義的變數)
描述帶有自由變數的代碼塊的技術名詞是閉包,在java中,lambda表達式就是閉包。
值得註意的是lambda表達式可以捕獲閉合作用域的變數值而不是變數。
public static void repeat(String msg ,int count){
for(int i = 0;i<count;i++){
new Thread(()->{System.out.println(i);});//不能捕獲i,因為i會變化,lambda表達式只能訪問來自閉合作用域的final局部變數。
}
}

public static void repeat(String[] msg ,int count){
for(String arg:msg){
new Thread(()->{System.out.println(msg);}).start();
//這個是可以的,因為每一次迭代都會創建一個新的arg變數,作用域是單個迴圈,而上面的i的作用域是整個迴圈
}
}
值得註意的是,lambda表達式不能改變任何捕獲的變數。例如修改上面的arg

高階函數
1. 返回函數的方法
public static Comparator<String> compareInDirection(int direction){
return (x,y)->direction*x.compareTo(y);
}
調用 compareInDirection(1)產生升序比較器, 調用 compareInDirection(-1)產生降序比較器
結果可以傳遞個另一個期望這個介面的方法(Arrays.sort)
Arrays.sort(friends,compareInDirection(1))
2. 修改函數的方法
public static Comparator<String> reverse(Comparator<String> comp){
return (x,y)->comp.compare(x,y);
}
它接收一個函數並返回一個修改後的函數
reverse(String::compareToIgnoreCase)//獲得大小寫不敏感的降序

局部內部類
public static IntSequence randomInts(int low,int high){
class RandomSequence implements IntSequence{
public int next(){return low+generator.nextInt(high-low);};
public boolean hasNext() {return true;}
}
return new RandomSequence();
};
創建局部類的好處,其一,類名稱隱藏在方法範圍內。其二,局部類的方法可以訪問來自閉合作用域的變數,就像lambda表達式的變數。

匿名類(上面的RandomSequence只調用了一次,用來構造返回值,所以可以使用匿名類)
public static IntSequence randomInts(int low,int high){
return new IntSequence(){
public int next(){return low+generator.nextInt(high-low);};
public boolean hasNext() {return true;}
};
};


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • "Java代理設計模式 靜態代理" "Java中的動態代理 調用處理器" 代理設計模式的UML圖: 我將首先介紹Java中的各種代理實現方法 Java代理設計模式 靜態代理 這個例子非常簡單,只有一個方法 的介面 : 測試代碼: 測試輸出: 現在麻煩的是,Jerry的領導因為團隊中的開發者像Jerr ...
  • 1、問題描述與要求 模擬某校九層教學樓的電梯系統。該樓有一個自動電梯,能在每層停留,其中第一層是大樓的進出層,即是電梯的“本壘層”,電梯“空閑”時,將來到該層候命。 電梯一共有七個狀態,即正在開門(Opening)、已開門(Opened)、正在關門(Closing)、已關門(Closed)、等待(W ...
  • 由於教程是圍繞著文件打開做的錯誤處理,所以先記錄幾個用於文件處理的一些函數,fopen 用於打開一個文件;file_exists 用於檢查目錄是否存在;fclose( $變數 )用於指定關閉打開的文件; PHP處理錯誤的幾種方式:die()語句;自定義錯誤和錯誤觸發器;錯誤日誌; die()語句: ...
  • 在對比醫院業務數據中的各類藥品價格的時候,面對著成千上百種的藥品。因而想到使用爬蟲來自動獲取網上的藥品價格,保存下來導入資料庫中就可以方便地比較院方的藥品採購價格了。 通過百度搜索“藥品價格查詢”,在眾多的網站中,這裡選擇了藥價查詢網(http://www.china-yao.com/),主要是因為 ...
  • 採用ID3演算法 (信息熵:H(X)=−∑i=0np(xi)log2p(xi)) 下載一個決策樹可視化軟體:Graphviz (註意環境變數Path加:C:\Program Files (x86)\Graphviz2.38\bin) 代碼: 導入需要用到的庫: 讀取表格: 這裡一些數據(屬性),決定一 ...
  • 1.修改tp5/application/index/controller/Index.php內容。 2.修改tp5/application/index/view/index/index.html頁面內容。 ...
  • Maven的多模塊可以讓項目結構更明確,提高功能的內聚,降低項目的耦合度,真正的體現出分層這一概念。 我們在操作中,要明白為什麼這樣做,要瞭解到更深的層次,這樣,我們就不限於個別軟體了。 話不多說,直入主題: 如果對Maven還不夠熟悉,請看該博客:Maven基礎 整個項目做完之後的結構是這樣的: ...
  • 從官網上下載php後(我下的是php7.2.3版本),本想做個mysql的連接,但是無論怎麼配置mysqli擴展,發現mysqli都沒法用。 從百度上搜的那些方法都沒法用,發現都是一些在php.ini中配置extension=php_mysqli.dll,事實上這句話沒用了。 於是我仔細看了一下ph ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...