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:
댓글 쓰기