SW/Groovy

Groovy : Closures 개념, 예제, 설명, 방법

얇은생각 2025. 1. 10. 07:30
반응형

Groovy는 강력한 스크립트 언어로, 독창적인 기능으로 코딩을 간소화합니다. 그중 하나가 closures입니다. Java를 사용해본 적이 있다면 Groovy의 closures를 Java의 lambda와 비슷하지만 더 유연하다고 생각할 수 있습니다. 이 글에서는 Groovy closures의 생성, 사용 및 최적화 방법을 다루겠습니다.

 

Groovy : Closures 개념, 예제, 설명, 방법

 

Groovy에서 Closures란?

Closures는 변수에 할당하고, 전달하며, 필요할 때 실행할 수 있는 코드 블록입니다. 익명 함수와 Java의 lambda 조합이라고 생각하면 됩니다. 기능을 캡슐화하여 간결하고 재사용 가능한 코드를 작성할 수 있습니다.

다음은 closure의 간단한 예입니다:

// 간단한 closure 생성
def c = { println("Closures are super simple!") }
// closure 호출
c.call()

위 예제에서 {}를 사용해 closure를 생성하고 변수 c에 할당했습니다. 그런 다음 c.call()을 사용해 closure를 호출할 수 있습니다. 간단한 구조 덕분에 closures는 함수에 쉽게 전달하고 코드의 여러 부분에서 재사용할 수 있습니다.

 

첫 번째 Groovy Closure 생성하기

Groovy에서 closure를 생성하려면 중괄호 {}만 있으면 됩니다. 다음은 첫 번째 closure를 생성하는 단계별 과정입니다:

  1. IDE 열기: IntelliJ IDEA나 VS Code와 같은 편집기를 사용해 새로운 Groovy 스크립트를 생성하고 이름을 ClosureDemo로 지정
  2. Closure를 변수에 할당하기:
    def c = { println("Hello from the closure!") }
  3. Closure 호출하기: c() 또는 c.call()로 closure를 호출
    c.call() // 출력: Hello from the closure!

이제 Groovy closures의 마법이 시작됩니다. 다른 메서드에 전달하거나 기본 인수로 할당하고 closure 내부에 로직을 정의할 수 있습니다.

 

Groovy Closures에 매개변수 전달하기

Java lambda처럼 Groovy의 closures도 매개변수를 받아 실행되는 로직을 사용자 정의할 수 있습니다. 다음은 closure에 매개변수를 전달하는 방법입니다:

// 매개변수가 있는 closure 정의
def checkEvenOdd = { n ->
    println n % 2 == 0 ? "Even" : "Odd"
}

// 매개변수를 사용해 closure 호출하기
checkEvenOdd(4) // 출력: Even

위 예제에서 매개변수 n을 받아 숫자가 짝수인지 홀수인지 확인하는 closure checkEvenOdd를 정의했습니다.

 

개인적인 경험: Closures로 코드 간소화

Java에서 Groovy로 전환한 후 첫 프로젝트에서 컬렉션을 반복하고 데이터를 변환하며 필터를 적용하는 코드를 단순화하는 작업을 맡았습니다. 전통적인 Java 방식으로 여러 클래스를 정의하고 반복문을 사용했지만 번거로웠습니다.

그러다 Groovy closures를 사용하면서 코드를 몇 줄로 간결하게 줄일 수 있었습니다. 유지보수도 쉬워지고 실행 속도도 빨라졌습니다. closures 덕분에 코드가 해야 할 일의 개요처럼 보였고, 이는 나중에 코드를 읽는 사람의 부담을 줄였습니다.

 

Elvis 연산자: 코드를 간결하게

Groovy closures에서 사용할 수 있는 주요 도구 중 하나가 Elvis 연산자(?:)입니다. Java의 삼항 연산자와 비슷하지만 더 간결합니다. closure에서 이를 사용하는 방법을 보겠습니다:

// 매개변수와 Elvis 연산자를 사용하는 closure
def checkValue = { n = 2 ->
    println n % 2 == 0 ? "Even" : "Odd"
}

checkValue()    // 출력: Even (기본값 사용)
checkValue(3)   // 출력: Odd

위 예제에서 기본값(n = 2)을 제공하여 인수가 전달되지 않아도 closure가 작동하도록 했습니다. 이는 closures를 더 유연하고 오류에 강하게 만들어줍니다.

 

Closures는 일급 시민

Groovy에서 closures는 일급 시민입니다. 즉, 변수에 할당하거나 인수로 전달하고, 다른 함수에서 반환할 수 있습니다. 다음은 closures를 사용해 코드를 동적으로 만드는 예입니다:

def operateOnNumber = { n, closure -> closure(n) }

// 사용할 closures 정의
def doubleIt = { it * 2 }
def squareIt = { it * it }

// operateOnNumber를 다른 closures와 함께 호출하기
println operateOnNumber(4, doubleIt)   // 출력: 8
println operateOnNumber(4, squareIt)   // 출력: 16

operateOnNumber는 숫자와 closure를 받아 다른 closures를 전달하여 동작을 동적으로 변경합니다. 이를 통해 closures의 유연성과 재사용성을 보여줍니다.

 

컬렉션과 함께 Closures 사용하기

Groovy는 컬렉션 작업을 closures 덕분에 쉽게 처리할 수 있습니다. Java 스트림을 사용해본 적이 있다면 Groovy의 컬렉션 메서드인 each, collect 등을 쉽게 이해할 수 있을 것입니다:

def numbers = [1, 2, 3, 4, 5]

// 각 요소를 반복하기 위해 closure 사용
numbers.each { println it }

// collect를 사용해 컬렉션 변환
def squares = numbers.collect { it * it }
println squares // 출력: [1, 4, 9, 16, 25]

위 예제에서 eachnumbers 리스트의 각 요소를 반복하고, collect는 각 요소에 closure를 적용해 새 리스트를 만듭니다. 이러한 간결한 구문 덕분에 Groovy는 컬렉션 작업에 이상적입니다.

 

Groovy에서 Closures의 강력함

Closures는 Groovy의 다른 부분과 매끄럽게 통합됩니다. 예를 들어, times 메서드를 살펴보겠습니다:

4.times { println it }

times 메서드는 closure를 인수로 받아 0부터 시작해 특정 횟수만큼 실행합니다. 위 코드는 다음과 같이 출력됩니다:

0
1
2
3

Groovy에는 times와 같은 closure를 받아 최소한의 코드로 복잡한 작업을 수행하는 메서드가 많이 있습니다.

 

Groovy Closures 최적화 팁

  1. 간결하지만 가독성 있게 유지하기: Groovy closures는 간결한 코드를 작성할 수 있지만 가독성도 중요, 기본 변수 이름 it은 유용하지만 명확하지 않을 때는 매개변수의 이름을 명시적으로 지정
  2. 기본값 사용하기: 매개변수의 기본값을 사용해 closures를 견고하게 만들고 null 포인터 예외를 방지
  3. 재사용성을 위해 Closures 사용하기: 로직을 재사용하려면 closure로 추출해 다른 메서드나 객체에 전달하는 것을 고려

 

Closures 사용 시 주의할 점

  1. Null 포인터 예외: 매개변수 값이나 기본값을 제공하지 않으면 null 포인터 예외가 발생, 항상 매개변수를 적절히 처리
  2. it의 과도한 사용: it을 사용하면 코드가 짧아지지만 중첩된 closures에서는 가독성 하향, 필요하면 명시적인 매개변수 이름을 사용
  3. 복잡한 Closures: Closure가 너무 길어지면 여러 작은 closure나 전용 메서드로 리팩토링

 

Groovy Closures의 매력

Closures는 Groovy의 가장 강력한 기능 중 하나로, 코드의 길이를 줄이고 읽기 쉽게 만듭니다. 간단한 인라인 논리부터 복잡한 함수형 프로그래밍까지, closures는 Groovy를 매우 유연한 도구로 만듭니다. 리스트를 필터링하거나 데이터를 변환할 때 closures는 적은 노력으로 더 많은 작업을 수행할 수 있게 도와줍니다.

반응형