Scala memo (Scala + Java)
This post hasn't been updated for 9 years
Câu hỏi
1. Typesafe Inc
2. Có ranh giới giữa Scala và Java ?
3. SBT (Scala build tool)
4. Typesafe Activator
5. Nhúng Java vào Scala
6. Method trong Scala
7. Object trong Scala
8. Future trong scala
9. Sử dụng thư viện của java trên Maven reposite cho Scala
10 .Thanks
Trả lời
1. Typesafe Inc
Typesafe Inc
Là công ty xây dựng ra Scala language (https://www.typesafe.com/)- Cũng đồng thời là công ty tạo ra
Play framework
- Ngoài ra Typesafe còn cung cấp thêm một số tool phổ biến như :
- SBT : Scala build tool.
- Slick : Functional Relational Mapping for Scala.
- Eclipse for scala
2. Có ranh giới giữa Scala và Java ?
- Như đã biết Scala base trên Java, code scala sẽ được chạy trên JVM, Scala kế thừa được tất cả những
gì mà Java đã có
=> Không hề có một ranh giới nào giữa Scala với Java
- Có thể nhúng thoải mái code Java vào Scala và ngược lại
- Có thể sử dụng toàn bộ những gì Java có trong Scala,
- Có thể import một file
.java
vào file.scala
- Có thể sử dụng các thư viện
.jar
của Java vào một project Scala - Có thể Sử dụng toàn bộ thư viện trên
Maven repository
trong Scala app.
3. SBT (Scala build tool)
What is SBT ?
- SBT là một open-source tool cho Scala và Java project
- SBT tương tự
- Maven - Java
- Ant - Java
- Make - Linux
What is it use for ?
- SBT dùng để build ra một project Scala/Java
- SBT quản lý các thư viện trong một project Scala/Java (tương tự bundle-ruby)
Install SBT
echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 642AC823
sudo apt-get update
sudo apt-get install sbt
How to use ?
- SBT cho pháp định nghĩa ra một mô tả về project trong file
build.sbt
- Chạy project, test, build, compile ...., Manage library.
- Tạo một project Scala bằng sbt
$ mkdir hello
$ cd hello
$ vim build.sbt
$ mkdir -p src/main/scala/
$ sbt run
- => sau khi chạy những command trên thì
sbt
đã tạo ra một scala project trong folderhello
- Code ta tạo những file
.scala
và đặt trong src/main/scala - Chú ý : SBT ngu hơn maven hay những tool khác : nó không hề tạo cho chúng ta cấu trúc của 1 project (project layout folder) mà ta phải tạo bằng tay, thằng sbt nó dùng để chạy, build, test, quản lý thư viện.....
Cú pháp một file .stb
// Set the project name to the string "my-project" and the version to 1.0.0.
name := "my-project"
version := "1.0.0"
// Add a single dependency, for tests.
libraryDependencies += "junit" % "junit" % "4.8" % "test"
// Add multiple dependencies.
libraryDependencies ++= Seq(
"net.databinder" %% "dispatch-google" % "0.7.8",
"net.databinder" %% "dispatch-meetup" % "0.7.8"
)
SBT Commands
sbt clean
: Deletes all generated files (in the target directory).sbt compile
: Compiles the main sources (in src/main/scala and src/main/java directories).sbt run
: Runs the main class for the project in the same virtual machine as sbt.sbt console
: tarts the Scala interpreter with a classpath including the compiled sources and all dependencies
SBT with libraries (libraryDependencies)
- Khi muốn dùng một thư viện nào đó ta sẽ khai báo thư viện muốn dùng trong file
build.sbt
libraryDependencies ++= Seq(
"net.debasishg" %% "redisclient" % "3.0"
)
- Sau khi khai báo thêm mới (hoặc thay đổi version của thư viện)
trong file
build.sbt
ta chạysbt run
thì tự động thư viện sẽ được tìm kiếm trên reposite để dowload về hoặc được update version.
4. Typesafe Activator
What is it ?
- Là một tool dùng để tạo ra một
Play project
activator
: Base trênsbt
- Tương tự như
rails new
trong Rails framework ta có :activator new
trong Play
- Tương tự như
Install
- step 1: Dowload from > https://www.typesafe.com/get-started
- step 2: Sau khi nhận được 1 thư mục activator sẽ chứa một file
activator
- Để sử dụng ta sẽ buildpath vào .bashrc để dừng ở mọi nơi (nếu không mỗi khi dùng activator ta sẽ phải trỏ vào tận link tuyệt đối của file chứa activator.)
How to use :
- activator new => create a play project (rails new)
- activator run => run a project Play (rails server)
- activator shell => interact with project by terminal (rails console gọi irb)
activator shell
gọisbt
5. Nhúng Java vào Scala
- Ví dụ ở đây là : Trong một project Scala ta muốn sử dụng Date trong Java để xử lý dữ liệu kiểu Date
- Tạo file
UtilLogic.scala
package logics;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.text.SimpleDateFormat;
import java.text.DateFormat;
import java.util.Date;
import java.text.ParseException;
object UtilLogic {
def getAge(birthDate: String): Int = {
var formatter = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
var cal1 = Calendar.getInstance();
try{
var date = formatter.parse(birthDate);
cal1.setTime(date);
}catch{
case e: ParseException => e.printStackTrace();
}
var cal = new GregorianCalendar(cal1.get(Calendar.YEAR),
cal1.get(Calendar.MONTH), cal1.get(Calendar.DATE));
var now = new GregorianCalendar();
var res = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
if ((cal.get(Calendar.MONTH) > now.get(Calendar.MONTH))
|| (cal.get(Calendar.MONTH) == now.get(Calendar.MONTH)
&& cal.get(Calendar.DAY_OF_MONTH) > now.get(Calendar.DAY_OF_MONTH))){
res = res - 1;
}
return res;
}
}
- Lưu ý :
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
- =>
var formatter: SimpleDateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
- or :
var formatter = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
6. Method trong Scala
-
Khi viết hàm trong scala ta có 2 cách viết
-
def x() { // Trả về Unit (void) }
-
def x() = {// Trả về giá trị là giá trị của đoạn code cuối cùng của hàm}
-
Chú ý không nên viết return vì mặc định trả về kết quả của câu lệnh cuối cùng, nhưng trong 1 số trường hợp vẫn cầu return ví dụ như trong vong for
-
Không cần chỉ rõ giá trị trả về
-
Nếu một hàm không có tham số ta có thể viết
def x = { //hàm x không có tham số đầu vào + trả về giá trị là câu lệnh cuối cùng}
def x { //hàm x không có tham số đầu vào + trả về Unit (void) }
7. Object trong Scala
-
Khái niệm object trong Scala chính là khái niệm Static trong class cảu Java
-
Trong một object mọi thứ đều là
static
-
Mục đích của Object trong Scala là để dùng trong trường hợp chỉ cần 1 instance duy nhất của 1 class.
8. Future trong scala
Future Non-blocking scala
Khái niệm
- Future trong scala cung cấp cơ chế
non-blocking
xử lý song song - Mục đích cỦa Future : For the sake of performance and speed.
- Như List là đối tượng để lưu nhiều phần tử thì Future là một đối tượng để lưu kết quả của một tiến trình long-time
- Future là một object lưu một giá trị là kết quả trả về (result) của một
tiến trình nào đó. (tiến trình ở đây là một hàm tính toán, hay một hàm
access lấy dữ liệu trong db, hay một hàm cần long-time để trả về kết quả.)
- Trạng thái của Future object chính là trạng thái của tiến trình.
- Khi một tiến trình chưa hoàn thành thì Future cũng là chưa hoàn thành và ngược lại
- Future hoạt động như một Thread, Một khi có một future đc khởi tạo thì có thể coi một thread mới đc khởi tạo và chạy độc lập với Main thread.
Khởi tạo một Future
-
Future thuộc :
scala.concurrent.Future
-
import scala.concurrent package to make the type Future and the construct Future visible
-
Khi nào cần khởi tạo một Future:
- Khi một tiến trình (hàm) nào đó cần long-time
- Muốn tối ưu CPU
- Không muốn phải đợi cho đến khi một tiến trình (hàm) nào đó thực hiện xong mới làm những công việc khác mà ta có thể gọi tiến trình làm việc sau đó sẽ lấy kết quả ở một thời điểm khác.
-
Cú pháp tạo một Future bọc một tiến trình
- hàm
abc()
thực hiện cần long-time - hàm
abc()
trả về kiểu dữ liệu là T đã được đặt trong Future (Future[T])
- hàm
-
Future{ abc() }
: Future nhận đầu vào là một hàm, kết quả trả về là một Future với kiểu trả về và kiểu trả về của hàm -
Một Thread sẽ được tạo ra , Thread này có các tài nguyên chính là những tài nguyên nằm trong block {} bao gồm :
- biến
x
- hàm
abc()
- biến
-
Chú ý về Scope variable : Biến x chỉ tồn tại trong block của Future, ra khỏi block thì biến đó bị hủy.
val f: Future[T] = Future{
var x = 123
abc()
}
package src.main.scala
import com.redis._
import scala.concurrent._
import ExecutionContext.Implicits.global
object Hello {
val redis: RedisClient = new RedisClient("localhost", 6379)
def main(args: Array[String]) = {
println("Hi What the fuck!")
set
println(redis)
}
def set() = {
val f: Future[Boolean] = Future {
redis.set("key", "leminhtuan2015 cccc")
}
}
}
- ###Vậy để non-blocking một tiến trình nào đó ta chỉ cần bọc nó trong một Future
Future workflow
-
Cách thức hoạt động một Future như nào
-
Khi trình biên dịch (JVM) đọc đoạn code bên dưới thì nó tạo ra một thread mới
-
Thread này chạy song song với Main Thread
-
Tài nguyên cung cấp cho Thread này là phần nằm trong hai dấu
{ }
-
Tài nguyên của Future có thể là những biến chỉ tồn tại trong scope của Future đó,nhưng nó cũng có thể nhìn thấy những tài nguyên của scope bao bên ngoài nó như tào nguyên của class, của hàm chứa Future,
- Nếu là tài nguyên của riêng scope Future thì nó sẽ chỉ tồn tại trong phạm vi scope Future
- Nếu Future lấy những tài nguyên của scope rộng hơn nó (như class variable ) thì phải cẩn thận trong việc có nhiều Thread vì các thead đều share tài nguyên của class.
- ===>>> Tài nguyên của Class sẽ được Share cho tất cả các Future, Chỉ cần Một Future thay đổi giá trị của một Class variable thì giá trị đó bị thay đổi và vì thế phài quan tâm đến các tài nguyên dùng chung của nhiều thread (Tài nguyên găng)
-
val f: Future[Boolean] = Future {
redis.set("key", "leminhtuan2015 zzz")
}
Future callback
- Vậy ta đã có thể lập trình non-blocking cho những hàm long-time, và ta sẽ phải suy nghĩ là vậy quản lý việc trả lại kết quả của một Future như nào ???
- Future có một khái niệm là
callbacks
: Hàm callbacks sẽ được tự động trigger khi Future complete. - Như hàm f.onSuccess bên dưới thì nó tự động đc gọi khi Future completed.
- record chính là giá trị trả về cảu hàm
redis.set("key", "leminhtuan2015 zzz")
- record chính là giá trị trả về cảu hàm
package src.main.scala
import com.redis._
import scala.concurrent._
import ExecutionContext.Implicits.global
object Hello {
val redis: RedisClient = new RedisClient("localhost", 6379)
def main(args: Array[String]) = {
println("Hi What the fuck!")
set
println(redis)
}
def set() = {
val f: Future[Boolean] = Future {
redis.set("key", "leminhtuan2015 zzz")
}
f.onSuccess{ case record =>
println("record "+ record)
}
}
}
Future Blocking scala
- Như đã nói ở phần trên :
*Future hoạt động như một Thread, tiến trình đc bọc trong Future đc chạy
bằng một Thread đọc lập với main Thread và trả về kết quả bằng callback.*
- Vậy nhưng cũng có nhiều trường hợp ta phải cần đến
Blocking
(Tuần tự) và để lập trình Blocking trong Scala ta được hỗ trợ bởi- Future
- Promise
- Scala cung cấp 2 cách thức để thực hiện Blocking đó là :
- Await.ready => waits until the future becomes completed, nhưng không lấy lại đc kết quả của thread Future trả về
- Await.result => waits until the future becomes completed, Nhận lại đc kết quả của thread Future trả về
package src.main.scala
import com.redis._
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
object Hello {
val redis: RedisClient = new RedisClient("localhost", 6379)
def main(args: Array[String]) = {
println("Hi What the fuck!")
set
println(redis)
}
def set() = {
val f: Future[Boolean] = Future {
redis.set("key", "leminhtuan2015 zzz")
}
var result = Await.result(f, 1000 nanos)
println(result)
//f.onSuccess{ case record =>
// println("record "+ record)
//}
}
}
-
Khi sử dung
Await
thì code sẽ đượcblocking
(chạy tuần tự) Mail thread sẽ phải đợi cho đến khi Future chạy song thì nó mới chạy những câu lệnh bên dưới => Chốt lạiAwait
dùng để Tuần tự các Thread. -
Nhưng cái đáng lo ngại nhất khi dùng
Await
là ta phải xác định đctime-out
của một Future , Nghĩa là phải xác định (dự đoán) trong khoảng thời gian bao lâu thì future đó sẽ tính toán xong- Nếu ước lượng thời gian quá lớn thì không tốt
- Nếu ước lượng thời gian nhỏ quá thì bị bung ra lỗi time-out như bên dưới
java.util.concurrent.TimeoutException: Futures timed out after [1 nanosecond]
- Thường thường bạn sẽ sử dụng Future với những hàm tính toán long-time và khó ước lượng time, thêm vào đó nế đã muốn tuần tự thì bạn Dùng Future làm chi cho mệt!!!
9. Sử dụng thư viện của java trên Maven reposite cho Scala
Maven Central Reposite
Maven
-
Giống như:
- activator : Play (built.sbt)
- sbt : Scala (built.sbt)
- Ant : Java (pom.xml)
- Maven : Java (pom.xml)
-
Thì
maven
là một tool để quản lý project Java -
Maven có những tính năng sau
- Tạo ra một layout Structure Folder của một project Java
- Build
- Compile
- Run
- Test
- Deploy
- Managment Lib (Quản lý thư viện)
-
Ta có một Maven Repository chuyên để các thư viện của Java tương tự như Rubygem là server để quản lý các thư viện của Ruby
-
Với maven ta đặt các tự viện trong file pom.xml trong với cú pháp như sau
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.4.2</version>
</dependency>
</dependencies>
- Ngoài ra Server của Maven còn hỗ trợ những thư viện cho Scala, để láy về một thư viện trên Maven Repository về Scala app ta có thế add dòng code bên dưới vào file build.sbt
libraryDependencies += "redis.clients" % "jedis" % "2.4.2"
Thanks
- Please leave a comment so that i can better myself.
All Rights Reserved