2022년 10월 10일 월요일

let,apply,also,run,with를 Java처럼 사용하던 습관 고치기

let,apply,also,run,with를 Java처럼 사용하던 습관 고치기

let,apply,also,run,with를 Java처럼 사용하던 습관 고치기

Kotlin에서의 let,apply,also,run,with 를 처음보고 좀 이상하다 생각하다가 막상 써보고 나면 java에서도 그런형식으로 쓰고 싶은 욕망이 생긴다.
근데 문득 저 5가지를 잘 쓰고 있는가 생각했더니, 아니었다.
기존 코드도 리팩토링 겸 kotlin 처럼 코드를 작성하자.

  • let : 무의식적으로 null변수는 무조건 let으로 하고 있었는데, 무조건 사용하면 좋지않다.
  • 무조건 Null 체크할때 쓰면 불필요한 변수가 늘어난다. 특히, 불변의 변수는 let의 사용을 최대한 자제하자.
fun myLogic(){  
    val str:Int? = returnNull()  
    str?.let {  
  print(str.toString())  
    }  
}  
  
fun returnNull(): Int? {  
    return null  
}
// Java로 Decompile 해보자.
public final void myLogic() {  
   Object str = this.returnNull();  
   if (str != null) {  
      boolean var3 = false;  //불필요한 변수가 생긴다.
      boolean var4 = false;  //이 변수들은 해당 스코프내에 계속살아있어서 메모리를 차지한다.
      int var6 = false;  
      int var7 = str.length();  
      boolean var8 = false;  
      System.out.print(var7);  
   }  
  
}

// 예전방식대로 != null 체크해보자.
  
fun myLogic(){  
    var str:Int? = returnNull()  
    if (str != null) print(str.toString())  
}  
  
fun returnNull(): Int? {  
    return null  
}
// Java로 Decompile 해보자
public final void myLogic() {  
   String str = this.returnNull();  
   if (str != null) {  
      int var2 = str.length();  
      boolean var3 = false;  
      System.out.print(var2);  
   }  
  
}
// 함수인자로 사용할때도 Decompile해보면 결과는 같다.
myLogic(returnNull())
  • Global Scope변수나 현재의 스코프블럭이외에서 값이 null될 상황이 있는 변수라면 let을 사용한다.
  
class MainActivity : AppCompatActivity() {  
    var str:String? = null
  
	fun myLogic(){  
	    if(str != null) {  
	        print(str.length)  //str은 외부에 의해 언제 null이 될지도 모르기 때문에 str?length를 해야한다.
	    }  
	    str?.let{mystr -> print(str.length())} // 이렇게 하면 임시변수 let의 mystr이 null이 아닌 값을 보장하므로 문제없다.
	}  
}
  • apply : 빌더패턴+데코레이터패턴을 사용할때 처럼 자기자신의 속성을 변경하거나, 추가속성을 계속 추라할때 사용유용하다.
//인텐트선언시 자주하던 intent.putExtra.... 가 아니라 apply로 한번에 생성과 부가적인 데코레이터를 추가한다.
Intent(context, MyActivity::class.java).apply {
    // scope to configure object
    putExtra("data", 123)
	addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
})
// Person 객체에 name와 age가 있다면 선언과 함께 초기화된 자기자신을 peter에서 돌려준다.
val peter = Person().apply {  
  name = "Peter"  
  age = 18  
}
  • also : 수신된 객체(객체.also)를 그밖의(also)다른곳에 사용하고자 할때 사용한다. apply와 는 다르게 수신된 객체를 it 알리아스에 넣어서 수신된 객체의 속성을 변경하지 않도록 한다. 수신된 객체의 데이터의 유효형검사, 수신된 객체로 별도의 처리가 필요한경우 사용된다.
Intent(context, MyActivity::class.java).apply {  
  // scope to configure object  
  putExtra("data", 123)  
    addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)  
}).also { intent ->  
  // scope to consume the object  
  startActivity(this@FooActivity,intent)  
}
//또는 아래처럼 데이터 검증시에 사용된다.단 
class Book(author: Person) {  
    val author = author.also { who -> 
        requireNotNull(who.age)  
    }  
}
  • run : 블럭(스코프)를 지정하여 특정 객체를 해당블럭내에서만 처리하고 싶을때 사용한다. 처리가 끝난 블록의 맨마지막 줄에 처리되는 값이 리턴값이다. run스코프내에서의 this는 객체자신이다.
  • with : null아 아닌 변수에 대해 객체체인하지 않고 처리스코프를 따로 지정하고 싶을때 사용한다.
fun setup(binding:MainLayoutBinding) = with(binding)     
    textName.text = "ch8n"
    textTwitter.text = "twitter@ch8n2"
}

0 comments:

댓글 쓰기