[패캠 안드로이드] Part1 Ch1.4 코틀린 vs 자바

0
post-thumbnail

Part1 Ch1.4 코틀린 vs 자바

Null safe

  • Java:
Integer a = 100;
a = null;
//int 는 primitive 자료형으로 null로 초기화 할 수 없지만
//Integer 는 Wrapper 클래스(객체) 이르모 null로 초기화 가능

///중략///

a.sum(); //NullPointException 발생 가능
 
if(a != null){ // null safe 한 코드 구성
    a.sum(); 
}
//혹은 try catch 문으로 예외 처리 해야
  • Kotlin:
val b : Int? = 100 //null 허용하는 Int형
val c : Int = 100 //null 허용하지 않는 Int형

///중략///

b?.sum() //b = null인 경우 실행 X
c.sum()  //애초에 nullsafe

Scope Function (apply, with, let, also, run)

  • 코틀린 표준 라이브러리에 포함된 함수

  • 객체의 컨텍스트 내에서 코드 블럭을 실행하기 위한 목적만을 가진 여러가지 함수 제공
    -> 이런 함수들을 람다식으로 호출할 때, 이는 임시로 범위(scope)를 형성
    -> 이 범위 내에서는 객체의 이름이 없어도 객체에 접근할 수 있다

  • this
    this 키워드로 람다 수신자로서의 컨텍스트 객체를 참조합니다
    대부분의 경우, 수신 객체의 멤버에 접근할 때 this를 생략 가능하지만

  • it
    컨텍스트 객체를 람다 인자(argument)로 가지는 경우, 인자의 이름이 정해지지 않았다면 해당 객체는 암시적인 기본 이름인 it으로 접근할 수 있다

  fun main(args: Array<String>){
  	val sum: Int.(num : Int) -> Int = {this + it}
  	print(1.sum(2))
    // 출력 : 3
  }

Apply 함수

  • 객체의 확장/초기화에 사용
  • Java:
Person person = new Person();
person.firstName = "First";
person.lasttName = "Last";
  • Kotlin:
val person = Person.apply(){
    this.firstName = "First"
    this.lastName = "Last"
}

Also 함수

  • 객체의 유효성 확인 / 디버깅에 사용
  • Java:
int value = Random.nextInt(100);
System.out.print(value);

Random 클래스는 난수를 생성하는 클래스로 객체를 생성하여 사용한다
int nextInt(): int형 난수 반환
int nextInt(int n): 0~n 미만의 정수형 난수 반환

  • Kotlin:
Random.nextInt(100).also{
//인자의 이름 정해진 경우
    value -> print("getRandomInt() generated value $value")
}

Random.nextInt(100).also{
//인자의 이름 정해지지 않은 경우
    print("getRandomInt() generated value $it")
}

Let 함수

  • null이 아닌 객체에서 람다를 실행할 때 사용
  • Java:
Integer number = null;
String sumNumberStr = null;

if(number != null){
    sumNumberStr = " "+ sum(10, number);
}
Integer number = null;
String sumNumberStr = null;

if(number != null){
    sumNumberStr = ""+ sum(10, number);
}else{
    sumNumberStr = "";
}
  • Kotlin:
val = number : Int?
val sumNumberStr = number?.let{
    "${sum(10, it)}"
}
val = number : Int?
val sumNumberStr = number?.let{
    "${sum(10, it)}"
}.orEmpty() //null인 String을 null이 아닌 ""로 초기화하는 String 멤버 함수

With 함수

  • Java:
Person person = new Person();

person.work();
person.sleep();
System.out.println(person.age);
  • Kotlin:
val person = Person()
with(person){
    this.work()
    this.sleep()
    print(this.age)
}

Run 함수

  • 객체의 초기화와 결과의 계산이 한번에 이루어질 때 사용
  • Java:
service.port = 8080;
Result result = service.query();
  • Kotlin:
val result = service.run{
    this.port = 8080
    query()
}

Data Class

  • Java: 하나의 클래스를 만들기 위해 여러줄의 코드 필요
public class JavaObject{
    private String s;

    //생성자
    JavaObject(String s){
        this.s = s;
    }
    //getter
    public String getS(){
        return s;
    }
    //setter
    public void setS(String s){
        this.s = s;
    }

    //copy
    //toString
    //hashCode 
    //equal 등등 생략
}
  • Kotlin: 멤버 함수 자동으로 구현됨 -> 한줄의 코드로 축약 가능
data class JavaObject(val s : String)

Lamda expression

button.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onCLick(View view){
        ...
    }
})
button.setOnClickListener{
    v-> ...
}

lateinit, lazyinit

  • nullsafe한 코드를 사용하기 위해 non-null Type으로 변수 선언할 때
    초기값이 없는 변수는 어떻게 선언해야할까?

  • lateinit: 변수의 값 초기화를 뒤로 미룸

var nullableNumber: Int? = null
lateinit var lateinitNumber : Int

//추후 초기화하는 코드
lateinitNumber = 10

//사용할 때
nullableNumber?.add()
lateinitNumber.add() //초기화를 하지 않으면 에러 발생
  • lazyinit: 변수를 미리 선언해놓고 사용할 때 값을 할당
val lazyNumber : Int by lazy{
    100
}
//사용하기 전까지는 lazyNumber라는 변수에 100이 할당되지 않는다

lazyNumber.add()
//사용할 때 100이 할당됨

📌참고자료

람다(Lambda)란?
익명 클래스가 이름없이 정의되어 사용될 수 있듯이 함수도 이름없이 사용되는 형태를 말한다 (Anonymous Function)

(People p1, People p2) -> p1.getAge().compareTo(p2.getAge());
  • Parameter list: (people p1, people p2)
  • 화살표: 람다의 파라미터와 바디를 구분
  • Lambda body: 람다의 반환값에 해당하는 표현식
(parameters) -> expression
(parameters) -> { statements; }

동작 파라미터화 (Behavior parameterization)
람다를 이용하면 함수의 인자로 어떤 동작을 하는 함수를 받을 수 있다
이 동작은 함수를 호출하기 전까지는 아직 정해지지 않은 상태이며, 함수를 호출할 때 전달해 준 동작을 이용해서 함수 내부가 구현된다

java.util.function package에서 가장 많이 사용하는 형태에 대한 interface를 framework단에서 제공한다 (Java8에서 추가된 package)

  • Predicate
    Lamda signature: (T) -> boolean
    Abstract method: boolean test(T t);
  • Consumer
    Lamda signature: (T) -> void
    Abstract method: void accept(T t);
  • Function<T,R>
    Lamda signature: (T) -> R
    Abstract method: R apply(T t);
  • Supplier
    Lamda signature: () -> T
    Abstract method: T get();
  • UnaryOperator
    Lamda signature: (T) -> T
    Abstract method: T apply(T t);

...은 매개변수를 받긴하지만 몇개인지 모른다라는 의미
즉, 몇 개의 매개변수를 넣어도 다 받을 수 있다

자바 람다식과 유사하다

fun main(args: Array) {
  val sum = { x: Int, y: Int -> println("Computing the sum of $x and $y...")
     x + y
  }
  println(sum(1, 2))
}
  • 중괄호로 감싼다 { .. }
  • 인자와 본문은 ->로 구분한다
  • 인자는 ()로 감싸지 않는다
  • 인자는 형식추론이 가능하므로 타입을 생략할 수 있다
  • 변수에 람다식을 담는경우에는 인자의 타입을 생략할 수 없다

코드의 간결성을 위한 규칙 존재

  • 함수의 맨 마지막 인자가 람다라면 () 안에서 빼내서 밖에 람다를 표현할 수 있다
  • 인자가 하나라면 그 인자는 람다식 내부에서 it으로 받을 수 있다
  • 인자가 하나이면서 그 인자가 람다타입 이라면 ()를 생략할 수 있다
people.maxBy ({p: Person -> p.age})
people.maxBy () {p: Person -> p.age}
people.maxBy {p: Person -> p.age}
people.maxBy {it.age}
profile
Be able to be vulnerable, in search of truth

0개의 댓글