SlideShare une entreprise Scribd logo
1  sur  73
Télécharger pour lire hors ligne
#JCConf
使用 Java 的 Future/Promise
API 來撰寫非同步程式
Koji Lin
JCConf 2015
#JCConf
使用 Java 的 Future/Promise
API 來撰寫非同步非阻塞程式
Koji Lin
JCConf 2015
About me
• Koji Lin
• @kojilin
• LINE Fukuoka, Japan
• 之前在 Cubie Inc.
• Android & iOS & 一些 Server side
大綱
• 非同步和非阻塞
• Java 8 前的方法
• j.u.c.CompletableFuture
什麼是非同步
• Asynchronous
• Not synchronous, or not
guaranteed to happen in the order
in which it appears in the code
from Playframework: Async, Reactive, Threads, Futures, ExecutionContexts
https://gist.github.com/sadache/4714280
什麼是非阻塞
• Non-blocking
• Doesn't cause the caller (Thread) to
be blocked waiting for a result,
from Playframework: Async, Reactive, Threads, Futures, ExecutionContexts
https://gist.github.com/sadache/4714280
為什麼?
• 有些工作很花時間
• 檔案讀寫
• 網路
• 加解密
• 圖片處理
壞處
• Web 服務,因為執行緒被長時間佔住,
提供的服務能處理的量降低
• 桌面或手機的應用,佔住執行緒會卡住
介面的反應,用戶體驗不佳
// 10 seconds
Image image1 = download(...);
render(image1);
// 12 seconds
Image image2 = download(...);
render(image2);
為什麼?
• 有些工作很花時間
• 想要更簡單的方式來控制流
程
Thread
• java.lang.Thread
• JDK 1.0
void downloadAsync(String url,
Consumer<Image> c) {
new Thread(() -> {
Image result = download(...);
c.accept(result);
}).start();
}
Thread 的缺點
• 常需配合用 synchronized, wait, notify
和 join
• 不同 Thread 間如何存取同一個變數
• 如何控管?
• 如何組合相依的工作
fetchDataAsync(data -> {
downloadAsync(data.avatar, image -> {
render(image);
});
});
new Thread(() -> {
final Data result = fetchData(...);
Image image = download(data.avatar);
Bitmap bitmap = decode(image);
...
}).start();
不易組合和再利用
• 組合各種非同步方法,寫起來會變成
callback hell
• 包一個外層的 Thread 執行
• 忘記包的話?
• 如何控制資源?
更複雜的組合
• 如果想要兩個任務結果都執行完畢
• 利用 Thread#join
• 如果只要任一個先取得該怎麼做?
• Thread#join(long millis) 和檢查結果
值
• 浪費一個 Thread 一直去做檢查
while(true) {
t1.join(1000);
if(t1Value != null) {
return t1Value;
}
t2.join(1000);
...
}
而且我們也不想再直接
使用 Thread API
Future
• java.util.concurrent.Future
• Java SE 5.0
• 一個等待結果的容器,讓我們可以需
要時嘗試去取得結果
ExecutorService service =
Executors.newCachedThreadPool();
Future<Image> f =
service.submit(() ->
downloadImage(...);
);
Future<Image> f = download(...);
Future<Image> f = download(...);
Future<Image> f = download(...);
... // 做點其他事情
Future<Image> f = download(...);
... // 做點其他事情
Image result = f.get();// 取得結果
阻塞
// 如果還沒有結果,會停住直到有結果
future.get();
阻塞
// 如果還沒有結果,會停住直到有結果
future.get();
future.get(5,
TimeUnit.SECONDS);
例外處理
try {
renderImage(future.get());
} catch(ExecutionException e) {
...
e.getCause();// 會是執行時丟的錯誤
}
其他方便的方法
future.cancel(boolean);
future.isCancelled();
future.isDone();
Future
• 從傳 callback 的方式,變成外部可以
自行再做處理
• 簡單易懂
• 只有 5 個方法
• 阻塞式的 API 來取得回傳
• 不易組合再利用
更複雜的組合
• 如果想要兩個任務結果都執行完畢
• 利用 Future#get
• 如果只要任一個先取得該怎麼做?
• Future#get(long, TimeUnit) 和檢查
結果值
• 浪費一個 Thread 一直去做檢查
CompletableFuture
• java.util.concurrent
• Java SE 8
• implements Future, CompletionStage
CF<String> cf = CompletableFuture
.completableFuture("Value");
CF<String> cf = CompletableFuture
.completableFuture("Value");
String result = cf.get();
CF<String> cf = CompletableFuture
.completableFuture("Value");
String result = cf.join();
CF<String> cf = CompletableFuture
.completableFuture("Value");
cf.thenAccept(
s -> System.out.println(s)
);
String load(){...}
...
CF<String> cf = CompletableFuture
.supplyAsync(() -> load());
CF<String> cf = CompletableFuture
.supplyAsync(() -> load(),
executorService);
CF<String> cf = ...;
CF<Integer> length = cf.thenApply(
data -> data.length()
);
cf.thenApplyAsync(
data -> data.length()
);
cf.thenApplyAsync(
data -> data.length(),
executorService
);
cf1 = cf.thenApplyAsync(...);
cf2 = cf.thenApplyAsync(...);
Task1
Task3
Task2
CF<String> cf = new
CompletableFuture();
cf.thenAccept(
s -> System.out.println(s)
);
CF<String> cf = new
CompletableFuture();
executor.submit(() -> {
String result = load();
cf.complete(result);
});
executor.submit(() -> {
try {
String result = load();
cf.complete(result);
} catch(Exception e) {
cf.completeExceptionally(e);
}
});
cf.whenComplete(
(String s, Throwable t) -> {
if(s != null)
System.out.println(s)
else
System.err.println(t)
}
);
How to change
existing code
CF<User> findUser(long uid){...};
CF<Image> download(User user){...};
CF<?> cf =
findUser(12L).thenApply(user ->
download(user)
);
CF<CF<Image>> cf =
findUser(12L).thenApply(user ->
download(user)
);
CF<File> cf = findUser(12L)
.thenCompose(
user -> download(user)
);
CF<File> cf = findUser(12L)
.thenCompose(
user -> download(user)
)
.thenCompose(
img -> save(img)
);
findUser(12L)
.thenApply(...)
.thenApply(...)// exception
.thenCompose(...)
.whenComplete(...);
allOf
CF<String> api1 = ...;
CF<String> api2 = ...;
CF<String> api3 = ...;
CF<Void> all =
CompletableFuture.allOf(api1,
api2, api3);
CF<List<String>> result =
all.thenApply(v ->
Arrays.asList(api1.get(),
api2.get(),
api3.get())
);
anyOf
CF<String> api1 = ...;
CF<String> api2 = ...;
CF<String> api3 = ...;
CF<Object> all =
CompletableFuture.anyOf(api1,
api2, api3);
App 中常見的行為
CF<User> findUser(String id);
CF<User> saveUSer(String id);
CF<Image> downloadAvatar(String id);
findUser(...)
.thenCompose(user ->
saveUser(user.id))
.thenCompose(user ->
downloadAvatar(user.id))
.thenAccept(img ->
render(img));
同時多 key 查詢
CF<Value> executeQuery(String id);
List<CF<Value>> queries =
ids.stream()
.map(id -> executeQuery(id))
.collect(toList());
//using allOf to let
//List<CF<Value>> -> CF<List<Value>>
CF<Void> all =
CF.allOf(queries.toArray());
CF<List<Value>> result =
all.thenApply(v ->
queries.stream()
.map(q -> q.join())
.collect(toList)
);
getOrderFromNetwork
getOrderFromDb
listProducts
getShipInfo
Data Flow
sendMail
• 事件驅動 (event driven)
• 容易組合 (easy to compose)
• 控制權可以回給呼叫者
• 減少 thread 的浪費
優點
• Future/Promise 的混合
• 不少語言實作是分開的
• 爆多的方法數量
• 60+
缺點
Demo
• CompletableFuture#cancel
• 不能取消正在執行的工作
• 盡量使用 Async 語尾的 API
注意
findUser
listArticles
listFriend
支援非同步的 WEB 框架
• Servlet 3.0 AsyncContext
• Spring Framework
• Controller 的回傳直接用 CompletableFuture
• Play Framework
• Asynchronous web framework
• play.libs.F.Promise
Web application
• 該不該用處理 http 的 thread 做事?
• Tomcat 有 max-threads 設定
• Play 本來就是 http 跟 worker 分離
• 每個要求的工作時間不一定相同
• 花多少時間?佔多少比例?
• 花時間的工作有沒有資源存取上限?
Simple Test
• Job: 1500ms ~ 30%, 100ms ~ 70%
• 無處理上限
• Tomcat max-threads 200
• ab -n 1000 -c 400
• Async ~375 requests/second
• Sync ~300 requests/second
Simple Test
• Job: 1500ms ~ 50%, 100ms ~ 50%
• 一次只能處理 30 件 1500 ms 的工作
• Async ~36 requests/second
• 50% < 2000ms
• Sync ~39 requests/second
• 50% < 5900ms
Android 不支援
Java 8 API
• Guava
• ListenableFuture
• RxJava
• Reactive Programming
• Bolts-Android
• Lambda !?
Reactive Programming
• Data flow
• Propagation of change
• Flow in Java 9 ?
Q&A

Contenu connexe

Tendances

Accelerate Development with NX Build System
Accelerate Development with NX Build SystemAccelerate Development with NX Build System
Accelerate Development with NX Build SystemThien Ly
 
Think Like a Hacker - Database Attack Vectors
Think Like a Hacker - Database Attack VectorsThink Like a Hacker - Database Attack Vectors
Think Like a Hacker - Database Attack VectorsMark Ginnebaugh
 
Black and Blue APIs: Attacker's and Defender's View of API Vulnerabilities
Black and Blue APIs: Attacker's and Defender's View of API VulnerabilitiesBlack and Blue APIs: Attacker's and Defender's View of API Vulnerabilities
Black and Blue APIs: Attacker's and Defender's View of API VulnerabilitiesMatt Tesauro
 
Clean architecture
Clean architectureClean architecture
Clean architecture.NET Crowd
 
Command Design Pattern
Command Design Pattern Command Design Pattern
Command Design Pattern anil kanzariya
 
Static Analysis Security Testing for Dummies... and You
Static Analysis Security Testing for Dummies... and YouStatic Analysis Security Testing for Dummies... and You
Static Analysis Security Testing for Dummies... and YouKevin Fealey
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by defaultSecuRing
 
Asynchronous Processing with Outbox Pattern in .NET Core 3.0
Asynchronous Processing with Outbox Pattern in .NET Core 3.0Asynchronous Processing with Outbox Pattern in .NET Core 3.0
Asynchronous Processing with Outbox Pattern in .NET Core 3.0Baris Ceviz
 
Splunk overview Russian
Splunk overview RussianSplunk overview Russian
Splunk overview RussianTimur Bagirov
 
PPT-Splunk-LegacySIEM-101_FINAL
PPT-Splunk-LegacySIEM-101_FINALPPT-Splunk-LegacySIEM-101_FINAL
PPT-Splunk-LegacySIEM-101_FINALRisi Avila
 
CSRF Attack and Its Prevention technique in ASP.NET MVC
CSRF Attack and Its Prevention technique in ASP.NET MVCCSRF Attack and Its Prevention technique in ASP.NET MVC
CSRF Attack and Its Prevention technique in ASP.NET MVCSuvash Shah
 
ZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORK
ZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORKZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORK
ZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORKMaganathin Veeraragaloo
 
Taylor Wicksell and Tom Gianos at SpringOne Platform 2019
Taylor Wicksell and Tom Gianos at SpringOne Platform 2019Taylor Wicksell and Tom Gianos at SpringOne Platform 2019
Taylor Wicksell and Tom Gianos at SpringOne Platform 2019VMware Tanzu
 
Peeling the Onion: Making Sense of the Layers of API Security
Peeling the Onion: Making Sense of the Layers of API SecurityPeeling the Onion: Making Sense of the Layers of API Security
Peeling the Onion: Making Sense of the Layers of API SecurityMatt Tesauro
 
API Security Best Practices & Guidelines
API Security Best Practices & GuidelinesAPI Security Best Practices & Guidelines
API Security Best Practices & GuidelinesPrabath Siriwardena
 
Modern application architectures
Modern application architecturesModern application architectures
Modern application architecturesAmazon Web Services
 

Tendances (20)

Accelerate Development with NX Build System
Accelerate Development with NX Build SystemAccelerate Development with NX Build System
Accelerate Development with NX Build System
 
Think Like a Hacker - Database Attack Vectors
Think Like a Hacker - Database Attack VectorsThink Like a Hacker - Database Attack Vectors
Think Like a Hacker - Database Attack Vectors
 
Black and Blue APIs: Attacker's and Defender's View of API Vulnerabilities
Black and Blue APIs: Attacker's and Defender's View of API VulnerabilitiesBlack and Blue APIs: Attacker's and Defender's View of API Vulnerabilities
Black and Blue APIs: Attacker's and Defender's View of API Vulnerabilities
 
Clean architecture
Clean architectureClean architecture
Clean architecture
 
Command Design Pattern
Command Design Pattern Command Design Pattern
Command Design Pattern
 
Static Analysis Security Testing for Dummies... and You
Static Analysis Security Testing for Dummies... and YouStatic Analysis Security Testing for Dummies... and You
Static Analysis Security Testing for Dummies... and You
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
 
MVP Clean Architecture
MVP Clean  Architecture MVP Clean  Architecture
MVP Clean Architecture
 
Asynchronous Processing with Outbox Pattern in .NET Core 3.0
Asynchronous Processing with Outbox Pattern in .NET Core 3.0Asynchronous Processing with Outbox Pattern in .NET Core 3.0
Asynchronous Processing with Outbox Pattern in .NET Core 3.0
 
Splunk overview Russian
Splunk overview RussianSplunk overview Russian
Splunk overview Russian
 
PPT-Splunk-LegacySIEM-101_FINAL
PPT-Splunk-LegacySIEM-101_FINALPPT-Splunk-LegacySIEM-101_FINAL
PPT-Splunk-LegacySIEM-101_FINAL
 
CSRF Attack and Its Prevention technique in ASP.NET MVC
CSRF Attack and Its Prevention technique in ASP.NET MVCCSRF Attack and Its Prevention technique in ASP.NET MVC
CSRF Attack and Its Prevention technique in ASP.NET MVC
 
ZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORK
ZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORKZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORK
ZERO TRUST ARCHITECTURE - DIGITAL TRUST FRAMEWORK
 
Android Pentesting
Android PentestingAndroid Pentesting
Android Pentesting
 
Taylor Wicksell and Tom Gianos at SpringOne Platform 2019
Taylor Wicksell and Tom Gianos at SpringOne Platform 2019Taylor Wicksell and Tom Gianos at SpringOne Platform 2019
Taylor Wicksell and Tom Gianos at SpringOne Platform 2019
 
Security testing
Security testingSecurity testing
Security testing
 
Peeling the Onion: Making Sense of the Layers of API Security
Peeling the Onion: Making Sense of the Layers of API SecurityPeeling the Onion: Making Sense of the Layers of API Security
Peeling the Onion: Making Sense of the Layers of API Security
 
API Security Best Practices & Guidelines
API Security Best Practices & GuidelinesAPI Security Best Practices & Guidelines
API Security Best Practices & Guidelines
 
Rbac
RbacRbac
Rbac
 
Modern application architectures
Modern application architecturesModern application architectures
Modern application architectures
 

En vedette

Using armeria to write your RPC
Using armeria to write your RPCUsing armeria to write your RPC
Using armeria to write your RPCkoji lin
 
Writing and using Hamcrest Matchers
Writing and using Hamcrest MatchersWriting and using Hamcrest Matchers
Writing and using Hamcrest MatchersShai Yallin
 
Java8 time
Java8 timeJava8 time
Java8 timekoji lin
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesHaim Yadid
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuturekoji lin
 
TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用Mark Chang
 
TypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript ComparisonTypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript ComparisonHaim Michael
 
TensorFlow 深度學習快速上手班--深度學習
 TensorFlow 深度學習快速上手班--深度學習 TensorFlow 深度學習快速上手班--深度學習
TensorFlow 深度學習快速上手班--深度學習Mark Chang
 
TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習Mark Chang
 
TensorFlow 深度學習講座
TensorFlow 深度學習講座TensorFlow 深度學習講座
TensorFlow 深度學習講座Mark Chang
 

En vedette (13)

Using armeria to write your RPC
Using armeria to write your RPCUsing armeria to write your RPC
Using armeria to write your RPC
 
Monoids
MonoidsMonoids
Monoids
 
Writing and using Hamcrest Matchers
Writing and using Hamcrest MatchersWriting and using Hamcrest Matchers
Writing and using Hamcrest Matchers
 
Java8 time
Java8 timeJava8 time
Java8 time
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFutures
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
 
TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用
 
TypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript ComparisonTypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript Comparison
 
TensorFlow 深度學習快速上手班--深度學習
 TensorFlow 深度學習快速上手班--深度學習 TensorFlow 深度學習快速上手班--深度學習
TensorFlow 深度學習快速上手班--深度學習
 
TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習
 
TensorFlow 深度學習講座
TensorFlow 深度學習講座TensorFlow 深度學習講座
TensorFlow 深度學習講座
 
Think Async in Java 8
Think Async in Java 8Think Async in Java 8
Think Async in Java 8
 
TENSORFLOW深度學習講座講義(很硬的課程)
TENSORFLOW深度學習講座講義(很硬的課程)TENSORFLOW深度學習講座講義(很硬的課程)
TENSORFLOW深度學習講座講義(很硬的課程)
 

Similaire à 使用 Java 上的 future/promise API

Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoloadjay li
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层yiditushe
 
Graphic programming in js
Graphic programming in jsGraphic programming in js
Graphic programming in jsjay li
 
Java script closures
Java script closuresJava script closures
Java script closuresskywalker1114
 
Java script closures
Java script closuresJava script closures
Java script closuresskywalker1114
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用Shengyou Fan
 
Symfony簡介
Symfony簡介Symfony簡介
Symfony簡介Ricky Su
 
廖雪峰 Saa s ovp
廖雪峰 Saa s ovp廖雪峰 Saa s ovp
廖雪峰 Saa s ovpdrewz lin
 
AngularJS training in Luster
AngularJS training in LusterAngularJS training in Luster
AngularJS training in LusterJason Chung
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计yiming he
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式Shengyou Fan
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非Tony Deng
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践taobao.com
 
Dive into kissy
Dive into kissyDive into kissy
Dive into kissyjay li
 
Koa 正在等一個人
Koa 正在等一個人Koa 正在等一個人
Koa 正在等一個人Fred Chien
 

Similaire à 使用 Java 上的 future/promise API (20)

Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
 
I os 07
I os 07I os 07
I os 07
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层
 
Graphic programming in js
Graphic programming in jsGraphic programming in js
Graphic programming in js
 
I os 16
I os 16I os 16
I os 16
 
Java script closures
Java script closuresJava script closures
Java script closures
 
Java script closures
Java script closuresJava script closures
Java script closures
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
 
Symfony簡介
Symfony簡介Symfony簡介
Symfony簡介
 
YUI 3 菜鳥救星
YUI 3 菜鳥救星YUI 3 菜鳥救星
YUI 3 菜鳥救星
 
廖雪峰 Saa s ovp
廖雪峰 Saa s ovp廖雪峰 Saa s ovp
廖雪峰 Saa s ovp
 
AngularJS training in Luster
AngularJS training in LusterAngularJS training in Luster
AngularJS training in Luster
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践
 
Dive into kissy
Dive into kissyDive into kissy
Dive into kissy
 
Koa 正在等一個人
Koa 正在等一個人Koa 正在等一個人
Koa 正在等一個人
 
OSGi Small Lab
OSGi Small LabOSGi Small Lab
OSGi Small Lab
 

Plus de koji lin

サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよkoji lin
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code genkoji lin
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Androidkoji lin
 
docker intro
docker introdocker intro
docker introkoji lin
 
Java8 stream
Java8 streamJava8 stream
Java8 streamkoji lin
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambdakoji lin
 
Raspberry Pi with Java
Raspberry Pi with JavaRaspberry Pi with Java
Raspberry Pi with Javakoji lin
 
Services you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile appServices you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile appkoji lin
 
Programming with Threads in Java
Programming with Threads in JavaProgramming with Threads in Java
Programming with Threads in Javakoji lin
 
山頂洞人日記 - 回歸到最純樸的開發
山頂洞人日記 -  回歸到最純樸的開發山頂洞人日記 -  回歸到最純樸的開發
山頂洞人日記 - 回歸到最純樸的開發koji lin
 
Android Location-based應用開發分享
Android Location-based應用開發分享Android Location-based應用開發分享
Android Location-based應用開發分享koji lin
 

Plus de koji lin (15)

サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよ
 
G1GC
G1GCG1GC
G1GC
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
 
Jcconf
JcconfJcconf
Jcconf
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Android
 
docker intro
docker introdocker intro
docker intro
 
Java8 stream
Java8 streamJava8 stream
Java8 stream
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambda
 
Idea13
Idea13Idea13
Idea13
 
Raspberry Pi with Java
Raspberry Pi with JavaRaspberry Pi with Java
Raspberry Pi with Java
 
Services you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile appServices you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile app
 
Programming with Threads in Java
Programming with Threads in JavaProgramming with Threads in Java
Programming with Threads in Java
 
JQuery
JQueryJQuery
JQuery
 
山頂洞人日記 - 回歸到最純樸的開發
山頂洞人日記 -  回歸到最純樸的開發山頂洞人日記 -  回歸到最純樸的開發
山頂洞人日記 - 回歸到最純樸的開發
 
Android Location-based應用開發分享
Android Location-based應用開發分享Android Location-based應用開發分享
Android Location-based應用開發分享
 

使用 Java 上的 future/promise API