본문 바로가기
그룹 스터디 공부(IT 서적)/모던 자바 인 액션

20.OOP와 FP의 조화:자바와 스칼라 비교

by hanyugyeong 2023. 10. 13.
반응형
SMALL

1.스칼라 소개

명령형, 함수형으로 구현된 Hello World예제 확인,

스칼라의 자료구조 확인(List, Set, Map, Stream, Tuple, Option...)

1. Hello Beer

  • 스칼라에서는 모든 것이 객체다. = 기본자료형(primitive)이 없다성
  • 스칼라는 자동으로 변수형을 추론하는 기능이 있다.
  • 모든 변수의 형식은 컴파일 할 때 결정된다.
// object로 클래스를 정의하고 동시에 싱글턴 객체를 만들었다.
object Beer {
// object 내부에 선언된 메서드는 정적 메서드로 간주되므로 static을 명시할 필요 없다.
def main(args: Array[String]) {
  var n : Int = 2
  while (n <= 6) {
    // 스칼라의 문자열 보간법 : 문자열에 접두어s를 붙이고, ${}안에 변수 위치
    println(s"hello ${n}")
    n += 1
  }
}
}
object Beer {
def main(args: Array[String]) {
  2 to 6 foreach { n => println(s"hello ${n}") }
  // 2.to(6).foreach(n => println(s"hello ${n}"))  //위와 동일
}
}

2. 기본 자료구조 : 리스트, 집합, 맵, 튜플, 스트림, 옵션

  • 컬렉션 만들기
object Beer {
def main(args: Array[String]) {
  // Map 선언 result : Some(23)
  var authorsToAge = Map("R" -> 23, "M" -> 40,  "A" -> 54)
  println(s"${authorsToAge.get("R")}")
  // List 선언 result : R M A 
  val authors = List("R", "M", "A")
  authors.foreach(name => print(s"${name} "))
  // Set 선언 result : 5 1 6 2 3 
  val numbers = Set(1, 1, 2, 3, 5, 6)
  numbers.foreach(number => print(s"${number} "))
}
}

3. 불변과 가변

  • 위 예제에서 만든 자료구조들은 불변객체
  • 갱신이 필요하면 새로운 컬렉션을 만들어야 함
object Beer {
def main(args: Array[String]) {
val authors = Set("R", "M", "A")
val newAuthors = authors + "B"
println(newAuthors) // Set(R, M, A, B)
}
}

4. 컬렉션 사용하기

object Beer {
def main(args: Array[String]) {
  val numbers = List("three", "four", "seven")
  val result = numbers.filter(n => n.length() > 4).map(n => n.toUpperCase())
  println(result)
  // List(THREE, SEVEN)
  val resultByUnderscore = numbers filter (_.length > 4) map (_.toUpperCase)
  println(resultByUnderscore)
  // List(THREE, SEVEN)
}
}

5. 튜플

  • 자바는 튜플을 지원하지 않는다. 필요하면 VO를 만들어써야지
  • 자바 14부터 튜플식으로 쓸 수 있는 record 지원
object Beer {
def main(args: Array[String]) {
val book = (2018, "Modern Java", "Manning")
val numbers = (2, 3, 4, 5)
println(book) // (2018,Modern Java,Manning)
println(numbers) // (2,3,4,5)
}
}

6.스트림

  • 스칼라의 스트림은 자바의 스트림보다 다양한 기능을 제공한다.
  • 이전 요소가 접근할 수 있도록 기존 계산 값을 기억한다.
  • 인덱스를 제공하기 때문에 리스트처럼 인덱스로 스트림 요소에 접근할 수 있다.
  • 자바의 스트림에 비해 메모리 효율성이 떨어진다.

7. 옵션

  • Optional 친구
def getCarInsuranceName(person: Option[Person], minAge: Int) =
person.filter(_.getAge >= minAge)
  .flatMap(_.getCar)
  .flatMap(_.getInsurance)
  .map(_.getName)
  .getOrElse("Unknown")

2. 함수

스칼라의 함수는 어떤 작업을 수행하는 명령어 그룹이다.

1. 스칼라의 일급 함수

  • Predicate함수를 저장해뒀다가 filter함수에 인수로 전달할 수 있다
object Beer {
def main(args: Array[String]) {
  def isJavaMentioned(tweet: String) : Boolean = tweet.contains("Java")
  val tweets = List("Java", "Scala")
  tweets.filter(isJavaMentioned).foreach(println)
}
}

 

2. 익명 함수와 클로저

  • scala.Function1형식의 익명 클래스를 축약한 다음 Function1의 apply호출
object Beer {
def main(args: Array[String]) {
  val isLong : String => Boolean = (tweet : String) => tweet.length > 60
  var result = isLong.apply("short tweet")
  println(result)
}
}

3. 클로저

  • 함수의 비지역 변수를 자유롭게 참조할 수 있는 함수의 인스턴스.
  • 자바의 람다에서는 람다가 정의된 지역 변수를 final로 취급해서 고칠 수 없는 제약이 있다
object Beer {
def main(args: Array[String]) {
var count = 0
// 람다 표현식인데 지역변수를 수정했다!
val inc = () => count += 1
inc()
println(count)  // 1
inc()
println(count)  // 2
}
}

4.커링

  • 스칼라에서는 커리된 함수를 직접 제공할 필요가 없다.
  • 함수가 여러 커리된 인수 리스트를 포함하고 있음을 가리키는 함수 정의 문법을 제공하기 때문이다.
object Beer {
def main(args: Array[String]) {
  // 인수 리스트 둘을 받는 함수
  def multiply(x : Int, y : Int) = x * y
  println(multiply(2, 10))  // 20
  // 파라미터 둘로 구성된 인수 리스트 하나를 받는 함수
  def multiplyCurry(x : Int)(y : Int) = x * y
  println(multiplyCurry(2)(10)) // 20
}
}

3. 클래스와 트레이트

자바의 클래스와 인터페이스를 스칼라와 비교

간결성을 제공하는 스칼라의 클래스

  • 스칼라는 완전한 객체지향 언어이므로 클래스를 만들고 객체로 인스턴스화 할 수 있다.
  • 생성자, 게터, 세터가 암시적으로 생성된다.
  • private var name해놓고 hello.name하면 안됨. hello.getName()도 없어서 새로만들어줘야됨
object Beer {
def main(args: Array[String]) {
  val hello = new Hello("dd");
  hello.sayThankYou // Thanks
  hello.name = "aa" // 이게 왜 세터?
  println(hello.name) // 이게 왜 게터?
}
class Hello(var name: String) {
  def sayThankYou() {
    println("Thanks")
  }
}
}

5. 스칼라 트레이트와 자바 인터페이스

  • 트레이트 : 추상화 기능으로 자바의 인터페이스와 유사
  • 추상 메서드와 기본 구현을 가진 메서드 모두 정의할 수 있음
  • 다중 상속 지원
  • 인스턴스화 과정에서도 조합할 수 있음. 신기하다
object Beer {
def main(args: Array[String]) {
  val isEmpty = new Empty().isEmpty();
  println(isEmpty)  //  true
  val sizedHello = new Hello("a") with Sized
  println(sizedHello.isEmpty()) //  true
}
class Hello(var name: String) {
  def sayThankYou() {
    println("Thanks")
  }
}
trait Sized {
  var size : Int = 0  // 필드
  def isEmpty() = size == 0  // 기본 구현을 제공하는 메서드
}
class Empty extends Sized { }
}

4. 마치며

  • 자바와 스칼라는 객체지향과 함수형 프로그래밍 모두를 하나의 프로그래밍 언어로 수용한다.
  • 두 언어 모두 JVM에서 실행되며 넓은 의미에서 상호운용성을 갖는다.
  • 스칼라는 자바처럼 다양한 추상 컬렉션을 제공한다. 튜플도(자바14에서는 자바도 record라고 튜플같은거 있음)
  • 스칼라는 자바에 비해 풍부한 함수 관련 기능을 제공한다.
  • 스칼라는 트레이트를 지원한다. 필드와 디폴트 메서드를 포함할 수 있는 인터페이스이다.
반응형
LIST