java 를 쓰다가 kotlin 으로 넘어오다 보니 여러 곳에서 stream 을 사용하다가 최근에 이런 리뷰를 받았다. kotlin에선 더 간결한 collection 함수를 제공하기 때문에 굳이 stream 을 사용할 필요가 없다는 것이다
코틀린을 자바같이 쓰면 앙대앙대
그래서 이 코드를 바꿧고 다시 리뷰를 받았는데
엉엉.... 마감은 다가오고
그래 이왕 이렇게 된김에 Stream 을 모두 한번 제거해보자 라는 생각이 들었다.
collection에 . 찍고 보면 뭐가 있을지 대충 보이잖아? 그래서 비교하며 간단히 메모해두려고 한다
Kotlin 으로 Map (key, value) 만들기
val dormantById = dormantRepository.findAll().stream()
.collect(Collectors.toMap(AccountDormant::id, Function.identity()))
Kotlin
복사
Java 인가 Kotlin 인가
이 코드는 다음과 같이 수정이 가능하다
val dormantById = dormantRepository.findAll().map { it.id to it }.toMap()
Kotlin
복사
그런데 똑똑한 IntelliJ 는 여기에 추천 코드를 보여줬다
val dormantById = dormantRepository.findAll().associateBy { it.id }
Kotlin
복사
왠지 이게 제일 맘에들어
3가지 모두 다 key-value 형태의 Map 을 만들어준다.
Kotlin 으로 Set (key) 만들기
val accountIds = items.stream().map {
it.id
}.collect(Collectors.toSet())
Kotlin
복사
Java 인가 Kotlin 인가
이 코드 역시 쉽게 변환이 가능하다
val accountIds = items.map {
it.id
}.toSet()
Kotlin
복사
처음엔 toSet() 을 바로 붙일 수 있는줄 알고 이러기도 해보고 저러기도 해봤다
kotlin 에서 map 이라는 친구는 stream().map 과 하는 행동이 비슷한가보다
/**
* Applies the given [transform] function to each element of the original collection
* and appends the results to the given [destination].
*/
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
for (item in this)
destination.add(transform(item))
return destination
}
Kotlin
복사
kotlin 에서 정의된 mapTo 라는 함수
transform 하는데 사용한다고 한다
Kotlin 으로 List 만들기
사실 딱히 예시가 없긴하지만 그래도 구색은 맞춰야 하니 한번 만들어보자
val accountIdList = accountRepository.findAll().stream()
.map{ it.id }
.collect(Collectors.toList())
Kotlin
복사
이상하게 이렇게 쓸 일은 없었다 코틀린 사용한지 이제 3개월 되었으니
val accountIdList = accountRepository.findAll().map {
it.id
}.toList()
Kotlin
복사
중요한건 map 인듯 하다
shuffle, entries
test 에서 id 하나를 추출하여 데이터를 삭제하고 다시 batch 를 수행하여 멱등성이 보장되는지 검증하는 코드가 있었다. 그 코드의 원본은 아래와 같았다
val account = dormantRepository.findByEmail("test1@gmail.com")!!
notificationRepository.deleteByAnotherId(account.anotherId)
notificationRepository.flush()
Kotlin
복사
문제는 deleteByAnotherId 라는 값이 test code 만을 위해 repository 에 생성된 코드인데 우리팀에서 이러한 코드는 지양하고 있다. 굳이 테스트를 위해서 어떠한 기능을 만들 필요는 없다고 여기고 있다.
그래서 다음과 같이 수정하였다.
val pick = dormantRepository.findAll().associateBy {
it.anotherId
}.entries.shuffled().first().also {
notificationRepository.delete(notificationRepository.findByAnotherId(it.value.anotherId)!!)
notificationRepository.flush()
}
Kotlin
복사
핵심은 collection API 에서 제공하는 entries 와 suffled 이다
/**
* Returns a read-only [Set] of all key/value pairs in this map.
*/
public val entries: Set<Map.Entry<K, V>>
Kotlin
복사
read-only 의 key-value entries 를 반환해준다
/**
* Returns a new list with the elements of this list randomly shuffled.
*/
@SinceKotlin("1.2")
public actual fun <T> Iterable<T>.shuffled(): List<T> = toMutableList().apply { shuffle() }
Kotlin
복사
이 코드에서 shuffle() 은 다음을 호출한다
/**
* Randomly shuffles elements in this mutable list.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.2")
public actual inline fun <T> MutableList<T>.shuffle() {
java.util.Collections.shuffle(this)
}
Kotlin
복사
그리고 이 shuffle 은 java.util.Collections 안에 있는 shuffle 이다.
그간 java 를 사용하면서 단 한번도 사용해본적이 없었는데 (그땐 이렇게 하드하게 테스트를 짜지 않았으니깐)
/**
* Randomly permutes the specified list using a default source of
* randomness. All permutations occur with approximately equal
* likelihood.
*
* <p>The hedge "approximately" is used in the foregoing description because
* default source of randomness is only approximately an unbiased source
* of independently chosen bits. If it were a perfect source of randomly
* chosen bits, then the algorithm would choose permutations with perfect
* uniformity.
*
* <p>This implementation traverses the list backwards, from the last
* element up to the second, repeatedly swapping a randomly selected element
* into the "current position". Elements are randomly selected from the
* portion of the list that runs from the first element to the current
* position, inclusive.
*
* <p>This method runs in linear time. If the specified list does not
* implement the {@link RandomAccess} interface and is large, this
* implementation dumps the specified list into an array before shuffling
* it, and dumps the shuffled array back into the list. This avoids the
* quadratic behavior that would result from shuffling a "sequential
* access" list in place.
*
* @param list the list to be shuffled.
* @throws UnsupportedOperationException if the specified list or
* its list-iterator does not support the {@code set} operation.
*/
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
Java
복사
List 가 shuffle 된다, 안전하게