티스토리 뷰

스트림 함수

컬렉션에 포함된 자료의 타입 변경 또는 새로운 자료 추가 생성을 쉽게 구현하기 위해 제공되는 함수

변환

  • map() : 컬렉션 내 인자를 함수에 정의된 규칙에 따라 다른 값 혹은 타입으로 변환할 때 사용
val cities = listOf("Seoul", "Tokyo", "Mountain View")

//도시 이름을 대문자로 변환
//출력 결과 : SEOUL TOKYO MOUNTAIN VIEW
cities.map{ city -> city.toUpperCase() }
	.forEach{ println(it) }

//도시 이름을 받아, 원소를 각 도시 이름의 문자열 길이로 변환
//출력 결과 : length=5 length=5 length=13
cities.map{ city -> city.length }
	.forEach{ println("length=$it") }
  • mapIndexed() : 컬렉션 내 포함된 인자의 인덱스 값을 변환 함수 내에서 사용 가능
  • mapNotNull() : 컬렉션 내 각 인자를 변환함과 동시에, 결과가 널 값인 경우 이를 원소에서 무시
  • flatMap() : map() 함수와 동일하나 하나의 인자에서 여러개의 인자로 매핑 가능
  • groupBy() : 컬렉션 내 인자들을 지정한 기준에 따라 분류하며, 각 인자들의 리스트를 포함하는 맵 형태로 결과 반환

필터

  • filter() : 컬렉션 내 인자들 중 주어진 조건과 일치하는 인자만 걸러주는 함수
val cities = listOf("Seoul", "Tokyo", "Mountain View")

//도시 이름의 길이가 5 이하인 항목만 통과
//출력 결과 : Seoul Tokyo
cities.filter { city -> city.length <=5 }
	.forEach { println(it) }
  • take() : 컬렉션 내 인자들 중 take() 함수의 인자로 받은 개수만큼만을 원소로 갖는 리스트 반환
  • takeLast() : 뒤에서부터 이 함수의 인자로 받은 개수만큼을 원소로 갖는 리스트 반환
  • takeWhile() : 첫번째 인자부터 시작하여 주어진 조건을 만족하는 항목까지를 포함하는 리스트 반환
  • takeLastWhile() : 뒤에서부터 주어진 조건을 만족하는 항목까지를 포함하는 리스트 반환
  • drop() : take() 함수와 반대, 컬렉션 내 인자들 중 조건을 만족하는 항목를 제외한 리스트 반환
  • dropLast() : 뒤에서부터 함수의 인자로 받은 개수만큼을 제외한 리스트 반환
  • dropWhile() : 첫번째 인자부터 시작하여 주어진 조건에 해당하는 항목을 제외한 리스트 반환
  • dropLastWhile() : 뒤에서부터 주어진 조건을 만족하는 항목까지를 제외한 리스트 반홤
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

//첫번째 인자로부터 하나의 인자만 포함하는 리스트를 출력
//출력 결과 : Seoul
cities.take(1)
	.forEach { println(it) }

//첫번째 인자로부터 하나의 인자를 제외한 리스트 출력
//출력 결과 : Tokyo Mountain View NYC Singapore
cities.drop(1)
	.forEach { println(it) }

//문자열의 길이가 5 이하인 조건을 만족할 때까지 해당하는 항목을 제외한 리스트 출력
//출력 결과 : Mountain View NYC Singapore
cities.dropWhile { city -> city.lenth <= 5 }
	.forEach { println(it) }
  • first() : 첫번째 인자 또는 특정 조건을 만족하는 첫번째 인자 반환, 조건을 만족하지 않으면 NoSuchElementException 예외 발생
  • last() : 마지막 인자 또는 특정 조건을 만족하는 마지막 인자 반환, 조건을 만족하지 않으면 NoSuchElementException 예외 발생
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

//문자열 길이가 5 이상인 첫 번째 인자 반환
//출력 결과 : Mountain View
println.first { city -> city.length > 5 }

//문자열 길이가 5 이하인 마지막 인자 반환
//출력 결과 : NYC
println.last { city -> city.length < 5 }
  • distinct() : 중복된 항목을 걸러낸 결과를 반환, 중복 여부는 equals()로 판단
  • distinctBy() : 중복된 항목을 판단하는 기준을 직접 설정 가능
val cities = listOf("Seoul", "Tokyo", "Mountain View", "Seoul", "Singapore")

//도시 목록 중 중복된 항목 제거
//출력 결과 : Seoul Tokyo Mountain View Singapore
cities.distinct()
	.forEach { println(it) }
    
//중복된 항목을 판단할 때, 도시 이름의 길이를 판단 기준으로 사용
//출력 결과 : Seoul Mountain View Singapore
cities.distinct { city -> city.length }
	.forEach { println{it} }

조합 및 합계

  • zip() : 두 컬렉션 내의 자료들을 조합하여 새로운 자료를 만들 때 사용, 기본값으로는 Pair로 결과를 만드며 조합 규칙 지정 가능
val cityCodes = listOf("SEO", "TOK", "MTV", "NYC")
val cityNames = listOf("Seoul", "Tokyo", "Mountain View")

//단순히 zip 함수를 호출하는 경우, Pair 형태로 자료 조합
//출력 결과 : SEO:Seoul TOK:Tokyo MTV:Mountain View
cityCodes.zip(cityNames)
	.forEach { pair -> println("${pair.first}:${pair.second}") }
    
//조합할 자료의 타입을 조합 함수를 통해 지정하면 해당 형태로 변환
//출력 결과 : SEO (Seoul) TOK (Tokyo) MTV (Mountain View)
cityCodes.zip(cityNames) { code, name -> "$code (#name)" }
	.forEach { println(it) }
  • joinToString() : 컬렉션 내 자료를 문자열 형태로 변환한 후 이를 조합하여 하나의 문자열로 생성, 인자 설정 가능
val cities = listOf("Seoul", "Tokyo", "Mountain View")

//출력 결과 : Seoul, Tokyo, Mountain View
println(cities.joinToString())

//출력 결과 : Seoul|Tokyo|Mountain View
println(cities.joinToString(seperator = "|"))
  • count() : 컬렉션 내 포함된 자료의 개수 반환, 조건식 추가 가능
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

//컬렉션의 모든 자료의 개수 반환
//출력 결과 : 5
println(cities.count())

//컬렉션 내 자료 중, 길이가 5 이하인 자료의 개수 반환
//출력 결과 : 3
println(cities.count { city -> city.length <= 5 })

기타

  • any() : 컬렉션 내 자료가 한개라도 존재하는지 여부를 Boolean으로 반환, 조건 추가시 조건식을 만족하는 자료의 유무 여부 반환
  • none() : 컬렉션이 비어있는지 여부를 Boolean으로 반환, 조건 추가시 조건식을 만족하는 자료의 유무 여부를 any()와 반대로 반환
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

//문자열 길이가 5 이하인 자료가 있는지 확인
//출력 결과 : true
print(cities.any { city -> city.length <= 5 })

//빈 문자열을 가진 자료가 없으면 true, 있으면 false 반환
//출력 결과 : true
print(cities.none { city -> city.isEmpty() })
  • max() : 숫자 타입의 컬렉션 내 최댓값 반환
  • min() : 숫자 타입의 컬렉션 내 최솟값 반환
  • average() : 숫자 타입의 컬렉션 내 평균값 반환
val numbers = listOf(4, 2, 5, 3, 2, 0, 8)

//출력 결과 : 8
println(numbers.max())

//출력 결과 : 0
println(numbers.min())

//출력 결과 : 5.5
println(numbers.average())

 


범위 지정 함수

'수신 객체(reciever)'와 '수신 객체 지정 람다(block)'를 공통적으로 가지는 함수

⭐️⭐️모든 함수의 반환값 = 람다(block) 함수의 반환값 = 람다(block) 함수의 마지막 줄⭐️⭐️

let()

  • fun <T, R> T.let(block: (T) -> R): R  : 함수를 호출한 객체를 이어지는 람다 함수에 매개 변수로 전달하며, 람다 함수의 결과값 반환
  • 불필요한 변수 선언 방지 가능
커스텀 뷰에서 패딩 값을 설정하는 코드

//단말기 환경에 맞게 패딩 값 계산
val padding = TypeValue.applyDimension(
	TypeValue.COMPLEX_UNIT_DIP, 16f, resources.displayMetrics).toInt()
//계산된 패딩 값 변수를 이용해 패딩 값 설정
setPadding(padding, 0, padding, 0)

=>

//let을 사용하여 padding 변수 선언 없이 계산된 패딩 값을 함수의 인자로 전달 가능
TypeValue.applyDimension(TypeValue.COMPLEX_UNIT_DIP, 16f,
	resources.displayMetrics).toInt().let {
    setPadding(it, 0, it, 0) //계산된 값을 인자로 받으므로, it 키워드로 함수에 바로 대입 가능
}
null 값이 아닌 경우를 체크한 후 특정 작업을 수행하는 코드

fun doSomething(message: String?) {
	//인자로 받은 message가 null이 아닌 경우에만 토스트로 메시지 표시
	if (null != message) {
    	Toast.makeTest(this, message, Toast.LENGTH_SHORT).show()
    }
}

=>

fun doSomeThing(message. String?) {
	//message가 null이 아닌 경우에만 let 함수 호출
    	message?.let{
    		Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
    	}
}

apply()

  • fun <T> T.apply(block: T.() -> Unit): T  :  함수를 호출한 객체를 람다 함수의 리시버로 전달하며, 함수를 호출한 객체를 반환
  • 람다 함수 내에서는 객체 이름 명시 없이 프로퍼티와 함수 직접 호출이 가능하므로, 프로퍼티에 값을 할당할 때 유용 ex) 객체 초기화
//param 객체의 여러 속성을 변경하기 위해 객체 이름을 계속하여 호출
val param = LineartLayout.LayoutParams(0, LinearLaout.LayoutParams.WRAP_CONTENT)
param.gravity = Gravity.CENTER_HORIZONTAL
param.weight = 1f
param.topMargin = 100
param.bottomMargin = 100

=> 

//apply() 함수에 이어지는 블록에 param 객체를 리시버로 전달하므로, 객체 이름 없이 직접 해당 객체의 속성에 접근 가능
val param = LinearLayout.LayoutParams(
	LinearLayout.LayoutParams.WRAP_CONTENT,
    	LinearLayout.LayoutParams.WRAP_CONTENT).apply {
    	gravity = Gravity.CENTER_HORIZONTAL
    	weight = 1f
    	topMargin = 100
    	bottomMargin = 100
}

with()

  • fun <T, R> with(reciever: T, block: T.() -> R): R  :  매개변수로 받은 객체를 람다 함수의 리시버로 전달하며, 람다 함수의 결과값 반환
  • 한 객체의 멤버에 반복해서 접근할 때 객체명을 일일히 명시하지 않고 멤버에 바로 접근 가능하며, 결과가 필요하지 않을 때 유용
  • 안전한 호출(?.)을 지원하지 않으므로, 널 값이 아닌 것으로 확인된 객체에 이 함수를 사용해야 함
fun manipulateView(messageView: TextView) {
	
    	//함수의 인자로 받은 messageView의 여러 속성을 변경
	with(messageView) {
    		//messageView 호출 없이 바로 속성값 변경 가능
    		text = "Hello, World"
        	gravity = Gravity.CENTER_HORIZONTAL
    }
}

run()

  • fun <R> run(block: () -> R): R  :  람다를 실행하고, 람다 함수의 결과값을 반환 (람다 함수의 마지막줄 반환)
  • 여러 임시 변수가 필요할 경우 또는 어떤 값을 계산해야할 때 유용
val padding = run {
	//이 함수 블록 내부에서 선언하는 값들은 외부에 노출되지 않음
	val defaultPadding = TypedValue.applyDimension(...)
    	val extraPadding = TypedValue.applyDimension(...)
    
    	//계산된 값 반환
    	defaultPadding + extraPadding
}
  • fun <T, R> T.run(block: T.() -> R): R  :  함수를 호출한 객체를 람다 함수의 리시버로 전달하며, 람다 함수의 결과값을 반환
  • with() 함수와 유사하나 run() 함수는 안전한 호출 사용이 가능하므로 널 값일 수 있는 객체에 사용할 때 유용
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        //엑티비티 생성 시, 기존에 저장된 값이 있는 경우 UI 복원 수행
        savedInstanceState?.run {
            
            //Bundle내에 저장된 값 추출
            val selection = getInt("last_selection")
            val text = getString("last_text")
            
            //UI 복원 수행
            ...
        }
    }

🕊고차함수 참고자료

 

코틀린 고차함수 run, apply, let, with 사용하기

run()에 대하여 run() 함수는 두 가지 형태로 사용 된다. 람다를 실행하고 그 결과값을 얻는 목적으로 사용하거나 객체의 멤버에 접근하기 위해 사용한다. run 함수의 매개변수에 함수 타입이 선언되어 있으므로..

ktko.tistory.com

 

코틀린 의 apply, with, let, also, run 은 언제 사용하는가?

원문 : “Kotlin Scoping Functions apply vs. with, let, also, and run”

medium.com

 

코틀린 헷갈리는 함수 정리. let, apply, run, with

코틀린 헷갈리는 함수 정리. let, apply, run, with 1. let let 함수를 호출하는 객체를 블록의 인자로 넘기고, 블록의 결과값을 반환한다. 또한 널 처리(if (a != null) 를 대신할 수 있다. inline fun <T, R> T...

jepark-diary.tistory.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함