網站首頁 編程語言 正文
標準函數with與run和apply with函數
with函數
接收兩個參數:第一個參數可以是任意類型的對象,第二個參數是一個Lambda表達式。with函數會在Lambda表達式中提供第一個參數對象的上下文,并使用Lambda表達式中的最后一行代碼作為返回值返回。
示例代碼如下:
val result=with(obj){
//這里是obj的上下文
"value"http://with函數的返回值
}
那么這個函數有什么作用呢?它可以在連續調用同一個對象的多個方法時讓代碼變得更加精簡,下面我們來看一個具體的例子。
比如有一個水果列表,現在我們想吃完所有的水果,并將結果打印出來,可以這樣寫
val list= listOf("Apple","Banana","Orange","Pear","Grape")
val builder=StringBuilder()
builder.append("Start eating fruits.\n")
for(fruit in list){
builder.append(fruit).append("\n")
}
builder.append("Ate all fruits.")
val result=builder.toString()
println(result)
這段代碼的邏輯很簡單,就是使用StringBuilder來構建吃水果的字符串,最后將結果打印出來
打印結果為:
觀察上述代碼,你會發現我們連續調用了很多次builder對象的方法。其實這個時候就可以考慮使用with函數來讓代碼變得更加精簡,如下所示:
val list= listOf("Apple","Banana","Orange","Pear","Grape")
val result= with(StringBuilder()){
append("Start eating fruits.\n")
for(fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result)
首先我們給with函數的第一個參數傳入一個StringBuilder對象,那么接下來整個Lambda表達式的上下文就會是這個StringBuilder對象。于是我們在Lambda表達式中就不用再像剛才那樣調用builder.append()和builder.toString()方法了,而是可以直接調用append()和toString()方法。Lambda表達式最后一行代碼會作為with函數的返回值返回,最終我們將結果打印出來。
雖然兩段代碼結果一樣,但是明顯第二段代碼的寫法更加簡潔一些,這就是with函數的作用。
run函數
run函數的用法和使用場景其實和with函數時非常類似的,只是稍微做了一些語法改動而已。首先run函數是不能直接調用的,而是一定要調用某個對象的run函數才行;其次run函數只接收一個Lambda參數,并且會在Lambda表達式中提供調用對象的上下文。其他方面和with函數一樣,包括也會使用Lambda表達式最后一行作為返回值返回。示例代碼如下:
val result=obj.run{
//這里是obj的上下文
"value"http://run函數的返回值
}
那么現在我們就可以使用run函數來修改一下吃水果的這段代碼,如下所示
val list= listOf("Apple","Banana","Orange","Pear","Grape")
val result=StringBuilder().run{
append("Start eating fruits.\n")
for(fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result)
總體來說變化很小,只是將調用with函數并傳入StringBuilder對象改成了調用StringBuilder對象的run方法,其他沒什么區別,這兩段代碼最終的執行結果是完全相同的。
apply函數
apply函數和run函數也是極其相似的,都是在某個對象上調用,并且接收一個Lambda參數,也會在Lambda表達式中提供調用對象的上下文,但是apply函數無法指定返回值,而是會自動返回調用對象本身。示例如下:
val result=obj.apply{
//這里是obj的上下文
}
//result==obj
那么現在我們再使用apply函數來修改一下吃水果的這段代碼
val list= listOf("Apple","Banana","Orange","Pear","Grape")
val result=StringBuilder().apply{
append("Start eating fruits.\n")
for(fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits.")
}
println(result.toString())
由于apply函數無法指定返回值,只能返回調用對象本身,因此result實際上是一個StringBuilder對象,所以我們在最后打印的時候還要調用它的toString()方法才行。這段代碼的執行結果和前面兩段仍然完全相同的。
其實with、run和apply這幾個函數的用法和使用場景是非常類似的。在大多數情況下,可以相互轉換。
例如我們啟動Activity的時候
val intent=Intent(this,SecondActivity::class.java)
intent.putExtra("param1","data1")
intent.putExtra("param2","data2")
startActivity(intent)
這里每傳遞一個參數就會調用一次intent.putExtra()方法,如果要傳遞10個參數,那就得調用10次。對于這種情況,我們就可以使用標準函數來對代碼進行精簡,如下所示
val intent=Intent(this,SecondActivity::class.java).apply{
intent.putExtra("param1","data1")
intent.putExtra("param2","data2")
}
startActivity(intent)
可以看到,由于Lambda表達式中的上下文就是Intent對象,所以我們不需要調用intent.putExtra()方法,而是直接調用putExtra()方法就可以了。傳遞的參數越多,這種寫法優勢也就越明顯。
定義靜態方法
靜態方法再某些編程語言里面又叫做類方法,指的就是那種不需要創建實例就能調用的方法,所有主流的編程語言都會支持靜態方法這個特性。
在java中定義一個靜態方法,只需要在方法上聲明一個static關鍵字就可以了,如下所示:
public class Util{
public static void doAction(){
System.out.printlin("do action")
}
}
上述代碼中的doAction()方法就是一個靜態方法。調用靜態方法并不需要創建類的實例,而是可以直接以Util.doAction()這種寫法調用。因而靜態方法非常適合用于編寫一些工具類的功能,因為工具類通常沒有創建實例的必要,基本上是全局通用的。
和大多數主流編程語言不同的是,kotlin卻極度弱化了靜態方法這個概念,想要在Kotlin中定義一個靜態方法反倒不是那么容易。
因為Kotlin提供了比靜態方法更好用的語法特性,那就是單例類
object Util{
fun doAction(){
println("do action")
}
}
雖然這里的doAction不是靜態方法,但是我們仍然可以使用Util.doAction()方式來調用,這就是單例類所帶來的便利。
不過,使用單例類的寫法會將整個類中所有方法全部變成類似于靜態方法的調用方式,而如果我們只是希望讓類中的某一個方法變成靜態方法的調用方式該怎么辦呢?這個時候就可以使用companion object了,示例如下:
class Util{
fun doAction1(){
println("do action1")
}
companion object{
fun doAction2(){
println("do action2")
}
}
}
首先我們將Util從單例類改成一個普通類,然后在類中直接定義一個doAction1()方法,又在companion object中定義了一個doAction2()方法。現在兩個方法就有了本質的區別,因為doAction1()方法是一定要先創建Util類的實例才能調用的,而doAction2()方法可以直接使用Util.doAction2()的方式調用。
不過,doAction2()方法其實也不是靜態方法,companion object這個關鍵字實際上會在Util類的內部創建一個伴生類,而doAction2()方法就是定義在這個伴生類里面的實例方法。只是Kotlin會保證Util類始終只會存在一個伴生類對象,因此調用Util.doAction2()方法實際上就是調用了Util類中伴生對象的doAction2()方法。
編譯成字節碼結果如下:
public final class Util {
public static final Util.Companion Companion = new Util.Companion((DefaultConstructorMarker)null);
public final void doAction1() {
String var1 = "do action1";
boolean var2 = false;
System.out.println(var1);
}
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004¨\u0006\u0005"},
d2 = {"Ltest/Util$Companion;", "", "()V", "doAction2", "", "kotlin01"}
)
public static final class Companion {
public final void doAction2() {
String var1 = "do action2";
boolean var2 = false;
System.out.println(var1);
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
由此看出,Kotlin中確實沒有直接定義靜態方法的關鍵字,但是提供了一些語法特性來支撐類似于靜態方法調用的寫法,這些語法特性基本上可以 滿足我們平時的開發需求了。
如果需要真正的靜態方法,Kotlin提供了兩種實現方式:注解和頂層方法。
先來看注解,前面的單例類和companion object都只是在語法的形式上模仿了靜態方法的調用方式,實際上他們都不是真正的靜態方法。因此如果你在Java中以靜態方法的形式去調用的話,你會發現這些方法并不存在。而如果我們給單例類或companion object中的方法加上@JvmStatic注解,那么Kotlin編譯器就會將這些方法編譯成真正的靜態方法,如下所示:
class Util{
fun doAction1(){
println("do action1")
}
companion object{
@JvmStatic
fun doAction2(){
println("do action2")
}
}
}
編譯成字節碼,此時doAction2()方法為靜態方法
public final class Util {
public static final Util.Companion Companion = new Util.Companion((DefaultConstructorMarker)null);
public final void doAction1() {
String var1 = "do action1";
boolean var2 = false;
System.out.println(var1);
}
@JvmStatic
public static final void doAction2() {
Companion.doAction2();
}
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007¨\u0006\u0005"},
d2 = {"Ltest/Util$Companion;", "", "()V", "doAction2", "", "kotlin01"}
)
public static final class Companion {
@JvmStatic
public final void doAction2() {
String var1 = "do action2";
boolean var2 = false;
System.out.println(var1);
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
注意@JvmStatic注解只能加在單例類或Companion object中的方法上,如果你嘗試加在一個普通方法上,會直接提示語法錯誤。
由于doAction2()方法已經成為真正的靜態方法,那么現在不管是在Kotlin中還是Java中,都可以使用Util.doAction2()的寫法來調用。
再來看頂層方法,頂層方法指的是那些沒有定義在任何類中的方法,比如我們編寫的main()方法。Kotlin編譯器會將所有的頂層方法全部編譯成靜態方法,因此只要你定義了一個頂層方法,那么它就一定是靜態方法。
想要定義一個頂層方法,首先要創建一個Kotlin文件。對著任意包名右擊→New→Kotlin File/Class,在彈出的對話框中輸入文件名即可。注意創建類型要選擇File,如圖所示
點擊“ok”完成創建,這樣剛剛的包名路徑下就會出現一個Helper.kt文件。現在我們再這個文件中定義的任何方法都會是頂層方法,比如這里我就定義一個doSomething()方法吧,如下所示:
fun doSomething(){
println("do something")
}
Kotlin會將所有的頂層方法全部編譯成靜態方法,那么我們要怎么調用這個doSomething()方法呢?
如果是在Kotlin中調用的話,所有的頂層方法都可以在任何位置被直接調用,不用管包名路徑,也不用創建實例,直接輸入doSomething()即可。
但如果在Java代碼中調用,你會發現找不到doSomething()這個方法,因為Java中沒有頂層方法這個概念,所有的方法必須定義在類中。那么這個doSomething()被藏在哪里呢?我們剛才創建的Kotlin文件名叫做Helper.kt,于是Kotlin編譯器會自動創建一個叫作Helperkt的Java類,doSomething()方法就是以靜態方法的形式定義在HelperKt類里面的,因此在Java中使用Helperkt.doSomething()的寫法來調用就可以了。
原文鏈接:https://blog.csdn.net/ChenYiRan123456/article/details/127624161
相關推薦
- 2022-12-01 C/C++細數宏與函數有那些區別_C 語言
- 2022-11-07 使用react-native-doc-viewer實現文檔預覽_React
- 2022-06-12 查看docker中運行的JVM參數問題及解決方法_docker
- 2023-02-01 C語言中聯合體與共用體和枚舉使用語法示例_C 語言
- 2022-11-23 GoLang?channel底層代碼實現詳解_Golang
- 2023-03-16 Android藍牙服務啟動流程分析探索_Android
- 2023-02-10 python自定義函數中的return和print使用及說明_python
- 2022-05-17 基于Pytorch的神經網絡之Regression的實現_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支