우테코 프리코스 및 최종 코딩 테스트에서는 ChatGPT 사용이 불가능합니다. 오직 구글링만 가능하죠. 하지만 막상 시험이 시작되면 "천 단위 콤마 어떻게 찍더라?", "입력 재시도 로직 어떻게 짰더라?" 헷갈려서 검색하느라 시간을 허비하게 됩니다.
역대 우테코 과제(편의점, 로또, 크리스마스, 다리 건너기 등)에서 공통적으로 사용되는 필수 유틸 코드를 한곳에 압축했습니다. 시험 시작하면 이 페이지 띄워두고 필요한 함수를 바로 복사해서 가져가세요.
1. 🔄 무한 재시도 (Retry) 로직
[출제 빈도 100%] 잘못된 입력 시 `[ERROR]` 출력 후 다시 입력받는 패턴입니다. View나 Controller에서 가장 먼저 세팅해야 할 함수입니다.
// 사용법: val result = retryUntilValid { inputView.readPayment() }
fun <T> retryUntilValid(action: () -> T): T {
while (true) {
try {
return action()
} catch (e: IllegalArgumentException) {
println(e.message) // [ERROR] 메시지 출력
}
}
}
2. 📝 문자열 파싱 & 컬렉션 변환
[출제 빈도 90%] 쉼표(,)로 구분된 입력, 대괄호([]) 제거, 숫자 변환 등 복잡한 입력을 깔끔하게 처리합니다.
object StringParser {
// 예: "pobi,woni,jun" -> List<String>
fun parseCommaSeparated(input: String): List<String> {
return input.split(",").map { it.trim() }
}
// 예: "1,2,3,4,5" -> List<Int> (로또)
fun parseIntList(input: String): List<Int> {
return parseCommaSeparated(input).map {
it.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자가 아닙니다.")
}
}
// 예: "[콜라-10],[사이다-3]" -> Map<String, Int> (편의점)
fun parseItemAndQuantity(input: String): Map<String, Int> {
val items = input.split(",")
val result = mutableMapOf<String, Int>()
for (item in items) {
// [ ] 제거 및 - 기준으로 분리
val cleanItem = item.replace("[", "").replace("]", "")
val parts = cleanItem.split("-")
require(parts.size == 2) { "[ERROR] 형식이 올바르지 않습니다." }
val name = parts[0].trim()
val quantity = parts[1].trim().toIntOrNull()
?: throw IllegalArgumentException("[ERROR] 수량은 숫자여야 합니다.")
result[name] = quantity
}
return result
}
}
3. 📅 날짜 및 요일 처리 (Date)
[출제 빈도 60%] 크리스마스 프로모션, 평일/주말 할인 등 날짜 계산이 필요할 때 씁니다.
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.format.DateTimeFormatter
object DateUtils {
// 오늘 날짜 가져오기 (camp.nextstep.edu.missionutils.DateTimes 사용 시)
// val now = DateTimes.now().toLocalDate()
// 문자열 -> 날짜 변환 ("2023-11-10")
fun parseDate(dateStr: String): LocalDate {
return LocalDate.parse(dateStr) // 기본 포맷 yyyy-MM-dd
}
// 특정 기간 내 포함 여부 (Start ~ End)
fun isWithinRange(date: LocalDate, start: String, end: String): Boolean {
val startDate = LocalDate.parse(start)
val endDate = LocalDate.parse(end)
return !date.isBefore(startDate) && !date.isAfter(endDate)
}
// 주말 판별 (금, 토) -> 미션마다 주말 기준이 다르니 주의!
fun isWeekend(date: LocalDate): Boolean {
val day = date.dayOfWeek
return day == DayOfWeek.FRIDAY || day == DayOfWeek.SATURDAY
}
}
4. 🎨 포맷팅 (화면 출력용)
[출제 빈도 80%] 돈(Currency), 정렬(Alignment), 리스트 출력을 예쁘게 할 때 씁니다.
import java.text.DecimalFormat
object Formatter {
private val moneyFormat = DecimalFormat("#,###")
// 10000 -> "10,000원"
fun toMoney(amount: Int): String {
return "${moneyFormat.format(amount)}원"
}
// 리스트 예쁘게 출력: [콜라, 사이다] -> "콜라, 사이다"
fun <T> joinList(list: List<T>): String {
return list.joinToString(", ")
}
// 영수증 줄 맞추기 (왼쪽 정렬, 오른쪽 정렬)
// %-10s: 왼쪽 10칸, %10s: 오른쪽 10칸
fun printReceiptLine(name: String, quantity: Int, price: Int) {
val priceStr = moneyFormat.format(price)
println(String.format("%-10s\t%10d\t%10s", name, quantity, priceStr))
}
}
5. 📂 파일 읽기 (Resource Loading)
[출제 빈도 40%] 편의점, 지하철 노선도 등 설정 파일을 읽어올 때 필수입니다. 주의: 경로에 공백/한글이 있을 경우 에러 방지를 위해 반드시 `.toURI()`를 써야 합니다.
import java.io.File
object FileReader {
fun loadResourceFile(fileName: String): List<String> {
val resource = javaClass.classLoader.getResource(fileName)
?: throw IllegalArgumentException("[ERROR] $fileName 파일을 찾을 수 없습니다.")
// .toURI() 필수!
return File(resource.toURI()).readLines()
.drop(1) // 헤더(첫줄) 버리기
.filter { it.isNotBlank() } // 빈 줄 무시
}
}
6. 🔍 Enum 검색 유틸
[출제 빈도 70%] 입력값(String)으로 일치하는 Enum 상수를 찾을 때 씁니다. `else` 처리를 깔끔하게 할 수 있습니다.
enum class Badge(val threshold: Int, val label: String) {
STAR(5000, "별"),
TREE(10000, "트리"),
SANTA(20000, "산타"),
NONE(0, "없음");
companion object {
fun findByAmount(amount: Int): Badge {
// 금액이 높은 순으로 정렬해서 찾기 (조건에 따라 로직 변경)
return entries.sortedByDescending { it.threshold }
.find { amount >= it.threshold }
?: NONE
}
fun findByName(name: String): Badge {
return entries.find { it.label == name }
?: throw IllegalArgumentException("[ERROR] 존재하지 않는 배지입니다.")
}
}
}
7. ✅ 공통 검증 로직 (Validation)
[출제 빈도 99%] 도메인 로직에 넣을 필수 검증들입니다.
object Validator {
// 숫자 범위 검증
fun validateRange(number: Int, min: Int, max: Int) {
require(number in min..max) { "[ERROR] $min ~ $max 사이의 숫자여야 합니다." }
}
// 중복 검증 (로또 번호 등)
fun validateDuplicate(numbers: List<Int>) {
require(numbers.distinct().size == numbers.size) { "[ERROR] 중복된 값이 있습니다." }
}
// 단위 검증 (1000원 단위 등)
fun validateDivisible(amount: Int, unit: Int) {
require(amount % unit == 0) { "[ERROR] $unit 단위로 입력해야 합니다." }
require(amount != 0) { "[ERROR] 0원은 입력할 수 없습니다." }
}
}
💡 마지막 꿀팁
- `require` vs `check`: 인자값 검증엔 `require`(IllegalArgumentException), 상태 검증엔 `check`(IllegalStateException)를 씁니다. 우테코는 주로 `IllegalArgumentException`을 요구하므로 `require`를 애용하세요.
- `String.format`: 영수증이나 표 출력이 나오면 탭(`\t`)만 믿지 말고 `%-10s` 처럼 자릿수를 확보하세요.
- 패키지 분리: 이 코드들을 `util` 패키지에 몰아넣고 시작하면 마음이 정말 편해집니다.
합격을 기원합니다! 화이팅! 💪
저도 열심히해서 합격하겠습니다 !!
'Dev Log > Kotlin' 카테고리의 다른 글
| [코틀린] 복잡한 '연속 근무 방지' 로직, Queue(큐) 하나로 깔끔하게 해결하기 (1) | 2026.01.07 |
|---|---|
| [우테코 | 안드로이드] 코틀린 최종 코딩테스트 준비, 과제 모음 (1) | 2026.01.06 |
| [우테코] 🏪 편의점 과제: 재고가 먼저인가 검증이 먼저인가? Controller와 Service의 역할 분담과 예외 처리 순서 (0) | 2026.01.06 |
| [Kotlin] 15줄 제한? 아니 10줄 제한! 메서드를 쪼개는 실전 리팩토링 가이드 (0) | 2026.01.06 |
| [우테코] 🏪편의점 미션: 흩어진 데이터를 하나의 객체로 모으는 기술 (feat. 프로모션/일반 재고 관리) (0) | 2026.01.06 |