국비교육(22-23)

72일차(1)/Android App(17) : Kotlin에서 java 클래스 사용, Lambda 표현식

서리/Seori 2023. 1. 18. 17:55

72일차(1)/Android App(17) : Kotlin에서 java 클래스 사용, Lambda 표현식

 

 

- 기존 코틀린 패키지에 우클릭해서 새 패키지 생성

com.example.kotlin_test.java

 

새 자바 클래스

Member

package com.example.kotlin_test.java;

public class Member {
    public int num;
    public String name;
    public String addr;

    public void showInfo(){
        System.out.println(num+"|"+name+"|"+addr);
    }
}

 

- 3개의 공개된 필드와 메소드 1개로 작성

 

- 이 자바 클래스를 코틀린에서 사용 가능할까?

 

 

package com.example.kotlin_test
import com.example.kotlin_test.java.MemberDto

fun main(){
    //kotlin에서 java 클래스도 자유롭게 import해서 사용할 수 있다.
    val mem1=com.example.kotlin_test.java.Member()
    mem1.num=1
    mem1.name="바나나"
    mem1.addr="서울"
    mem1.showInfo()

    val mem2=MemberDto()
    //내부적으로 java의 setter 메소드가 호출된다.
    mem2.num=2
    mem2.name="딸기"
    mem2.addr="부산"

    //내부적으로 java의 getter 메소드가
    val a = mem2.num;
    val b = mem2.name;
    val c = mem2.addr;
}

 

- java 패키지에 들어있는 member 를 import!

- 자동으로 import가 위에 들어오지 않으면 직접 입력해주면 된다.

 

- 객체 생성 방식, 코딩 방식만 좀 다를 뿐 java 클래스도 import해서 쓸수있다.

 

MemberDto 생성

package com.example.kotlin_test.java;

public class MemberDto {
    public int num;
    public String name;
    public String addr;

    public MemberDto(){}

    public MemberDto(int num, String name, String addr) {
        this.num = num;
        this.name = name;
        this.addr = addr;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}

 

- 위 MemberDto를 코틀린에서 import해서 가져와 보면,

 get, set 메소드 대신에 필드를 사용하는 느낌으로 메소드가 바뀌어 있다.

 

- 필드가 호출되는 것처럼 보이지만 클래스의 setter, getter 메소드를 호출하는 것

- 코틀린에서는 getter, setter 메소드를 이렇게 점을 찍어서 필드명으로 사용한다.

 


 

Step09_Lambda

package com.example.kotlin_test

/*
    Lambda expression (람다 표현식)
    - 익명 함수를 람다라고 한다.
 */

fun main(){
    //f1이라는 이름의 함수 만들기
    fun f1(){
        println("f1 함수 호출됨")
    }
    //만든 f1() 함수 호출하기
    f1()

    //이름이 없는 함수를 만들어서 바로 호출
    (fun(){
        println("익명 함수가 호출됨!")
    })()

    //이름이 없는 함수를 만들어서 변수에 담기
    val f2=fun(){
        println("f2함수가 호출됨!")
    }

    f2()
}

 

- 마치 자바스크립트 같은 모양이다.

- 메인함수 안에서 또다른 함수를 만들어서 호출하는 것이 가능

 

- java로 만들면 익명 이너클래스로 만들어서 f1 함수를 만들어놓고 그 객체의 메소드를 호출하는 방식으로 바뀔 것이다.

 

fun(){}

- 이름이 없는 함수. javascript 의 function(){} 과 같은 것!

- 이름없는 함수를 만들어서 바로 호출할 수도 있다.

 

- 함수 부분 (빨간색 박스) 뒤에 함수 호출 () 이 붙어있는 것!!

 

(fun(){
    println("익명 함수가 호출됨!")
})()

 

- 이런 형태로 작성 가능하다

- 코틀린의 작성방식은 매우 유연하다.

 


 

Step09_Lambda2

package com.example.kotlin_test

fun main(){
    /*
        in java => public void a(){}
        in kotlin => fun a():Unit{} or fun a(){}
        코틀린에서 Unit은 원시 타입이라고 지칭하고 java의 void 와 비슷한 역할을 한다.
     */
    fun a():Unit{
        println("a 함수 호출됨")
    }
    a()

    val isRun:Boolean=true
    var myName:String?=null
    myName="바나나"

    //함수를 만들어서 변수에 담고 싶다면...
    //type 추론이 가능하지만, 명시적으로 type을 표시하자고 한다면 어떻게 해야 할까?
    /*
        ()->Unit은
        1. 함수에 전달되는 인자는 없으며
        2. 아무값도 리턴하지 않는
        3. 함수 타입을 의미한다.
     */
    val b:()->Unit=fun(){
        println("b 함수 호출됨")
    }
    b()
    //fun() 생략 가능
    val c:()->Unit = {
        println("c 함수 호출됨")
    }
    /*
        (String)->String
        1. String type 인자를 하나 받아서
        2. String type 을 리턴해주는
        3. 함수 타입
     */
    val d:(String)->String = fun(name:String):String{
        return "내 이름은 ${name}"
    }

    //위를 아래와 같이 줄일 수 있다.
    val e:(String)->String = { name -> "내이름은 ${name}" }

    println(e("바나나"))

}

 

- 여기는 리턴 타입이 들어가는 자리이다.

- java라면 리턴하는 값이 어떤 것도 없다면 void라고 쓰는데,

 코틀린은 void 자리의 용어를 생략하거나 Unit 이라고 쓴다.

 

- Unit을 원시 타입이라고도 한다.

- 생략해도 되고 :Unit 을 작성해주어도 된다.

 

- 생략해도 된다면 굳이 Unit 이라는 예약어가 필요한 이유는?

- 함수를 담는 변수(b)의 타입은 뭐라고 적어주어야 할까?

 

- null이 가능한 타입은 ? 를 넣어주어야 한다. 이것이 없으면 null을 넣지 못한다.

 

:()->Unit

- 함수의 타입은 이렇게 표시해줄 수 있다. 함수 모양을 타입으로 전달할 수 있다.

 

- Unit 이라는 타입이 없다면 여기에 표시해줄 수가 없다.

- void 를 쓸 수도 없다(void는 예약어가 아니다). 그렇다고 비워두면 문법 오류가 일어난다.

- Unit아무것도 리턴하지 않는다 를 나타내는 예약어로써 사용한다!!

 

** ()->Unit
1. 함수에 전달되는 인자는 없으며
2. 아무 값도 리턴하지 않는
3. 함수 타입을 의미한다.

 

- 여기서 fun() 은 생략 가능하다.

 

- 이 함수의 타입은 무엇일까?

- string 타입을 인자로 받고 리턴 타입은 string이다. 하지만 함수타입은 string이 아니다.

 

val d :(String)->String

- 인자로 String 타입을 받고 String 타입을 리턴하는 함수 타입이다.

 

val e:(String)->String = { name -> "내이름은 ${name}" }

- 이렇게 작성할 수 있다.

 

- 매개변수에 전달된 값을 기억해서 안에 사용하겠다는 뜻!

- 이렇게 1줄로 작성하는 것을 기억하기!

 

- 이런 함수의 모양을 이해하고 작성할 수 있으면 된다.

 


 

Step09_Lambda3

package com.example.kotlin_test

//함수 type을 매개변수로 전달받는 함수
fun useFunc(f:()->Unit){
    //인자로 전달받은 함수 호출하기
    f()
}

//인터페이스 정의하기
interface Drill{
    fun hole()
}

fun useDrill(d:Drill){
    d.hole()
}

fun main(){

    useDrill(object:Drill{
        override fun hole() {
            println("구멍을 뚫어요!")
        }
    })

    //원래 모양
    useFunc(fun(){
        println("익명함수 호출됨! 1")
    })
    //fun() 생략
    useFunc({
        println("익명함수 호출됨! 2")
    })
    //위를 좀더 간단히 한 최종 모양
    useFunc {
        println("익명함수 호출됨! 3")
    }
}

 

- 함수를 매개변수로 받을 수 있다.

- 인자는 전달하지 않아도 되고, 리턴타입은 없는 함수를 사용

 

- 전달받는 함수의 모양을 강제하고 있다는 데에서 의의가 있다.★★

 

 

- 이 함수를 main 함수에서 만들어보려고 하면 이런모양이 나온다.

 

- 원래는 이런 모양이어야 하는데,

 

- 좀더 간단하게 작성할 수 있다. 최종적으로 이런모양이 된다.

- useFunc() 이라는 함수를 호출하면서 함수를 전달하는 구조이다.

 

- 이 안에 들어간 이것 자체가 함수이다!

 

- 같은 유형의 함수이기 때문에 그래서 useFunc() 안에 인자로 받아질 수 있는것이다.

 

interface Drill{
    fun hole()
}

fun useDrill(d:Drill){
    d.hole()
}

- 드릴 인터페이스타입을 전달받아서 hole 메소드를 사용하기!

 

- 메인 메소드 안에서 전달하려면 object 예약어와 함께 Drill 인터페이스 가져오기

- 익명 클래스를 사용해서 인터페이스의 참조값을 얻어내서 사용!