04. 그루비의 반복문과 제어문

그루비의 제어문



제어문을 판단하려면 문장의 참인지 거짓인지 여부(boolean type)을 체크 해야 합니다.
그 조건에 부합하는 계산을 하거나 조건식을 작성하려면 산술 연산자와 비교 연산자에 대해서 알아야 합니다.

아래는 기본적으로 자바에서도 쓰이고 있는 것을 포함한 그루비의 연산자입니다.




자주 안쓰는 것들도 있겠지만 전체적으로 자바 개발자들이 이해하는데 큰 무리가 없을 것입니다.

조건문 혹은 제어문



조건식을 만들기 전에 간단한 체크조건 소스를 보도록 하겠습니다.

package org.gliderwiki.project.operations

class CompareNull {
	static void main(args) {
		def a = null
		def b = "foo"
		
		println a != b
		println b != a
		println a == null
	}
}


실행해보면 결과는 모두 true 가 나옵니다. null에 대한 비교 역시 true가 나왔다는것이 핵심입니다.

코드를 조금 더 추가하여 테스트 해보도록 합니다.
Byte by = 12
Double dbl = 10
		
println by instanceof Byte
println dbl instanceof Double

println by > dbl


이것도 역시 실행해보면 true가 출력됨을 확인 할 수 있습니다.

기본적인 조건식 if 구문은 아래와 같습니다.

if(o == 'A') return true
else return false


물론, 자바에서 쓰이는 브레이스의 들여쓰기 규칙 또한 같게 적용하여 쓸 수 있습니다.

package org.gliderwiki.project.control

class EmptyString {

	static void main(args) {
		def s = ''
		if (s) {
			println "We've got a non empty string!"
		}
		else {
			println 'String is either null or empty'
		}
    }
}



실행을 해보면 " String is either null or empty " 구문이 출력되는데, null 이나 공백으로 초기화된 String 객체는 true 로 인식하지 않기 때문입니다. 이 구분에서 조건식을 if(s == '') 처럼 바꾸면 " We've got a non empty string! " 구문이 실행되는 것을 알 수 있습니다.

조건식 case문은 자바와는 다르게, 데이터 타입에서 좀 더 자유롭고 범위를 지정할 수 도 있습니다.

package org.gliderwiki.project.control

class RangeSwitch {

	static void main(args) {
		def rating = 4
		def feedback = ''
		
		switch (rating) {
			case 1..3 : 
				feedback = 'good'
				break
			case 4..6 :
				feedback = 'medium'
				break
			case 7..9 :
				feedback = 'poor'
				break
			default : 
			    feedback = 'unknown'
		}
		
		println feedback
	
		switch (rating) {
			case [1,2,3] :
				feedback = 'good'
				break
			case [4,5,6] :
				feedback = 'medium'
				break
			case [7,8,9] :
				feedback = 'poor'
				break
			default :
				feedback = 'default'
		}
		
		println feedback
    }
}



출력해보면 두 Case 문 모두 "medium" 이 출력되는 것을 확인 할 수 있습니다.
아래의 조금 더 복잡한 소스를 살펴보겠습니다.
package org.gliderwiki.project.control

class SwitchCase {

	static void main(args) {
		def values= [
			'abc': 'abc',
			'xyz': 'list',
			   18: 'range',
			   31: BigInteger,
		  'dream': 'something beginning with dr',
			 1.23: 'none',
		]
		values.each{
		  def result
		  switch( it.key ){
			case 'abc': //if switched expression matches case-expression, execute all
						//statements until 'break'
			  result= 'abc'
			  break
			case [4, 5, 6, 'xyz']:
			  result= 'list'
			  break
			case 'xyz': //this case is never chosen because 'xyz' is matched by
						//previous case, then 'break' executed
			  result= 'xyz'
			  break
			case 12..30:
			  result= 'range'
			  break
			case Integer:
			  result= Integer //because this case doesn't have a 'break', result
							  //overwritten by BigInteger in next line
			case BigInteger:
			  result= BigInteger
			  break
			case ~/dr.*/:
			  result= 'something beginning with dr'
			  break
			case {it instanceof Integer && it>30}: //use Closure
			  result= 'result is > 30'
			  break
			default:
			  result= 'none'
		  }
		  println it.value
		}
	}
}

자바에서의 Switch 구문보다 훨씬 다이나믹한 비교가 가능 합니다.

출력해본 결과는 아래와 같습니다.

결과
abc
list
range
class java.math.BigInteger
something beginning with dr
none


이 것과 덧붙여, break 구문과 continue 구문을 아래처럼 사용할 수 있습니다.

package org.gliderwiki.project.control

class BreakContinue {

	public static void main(args) {
		def a = 1
		
		while(true) {
			a++
			break
		}
		
		println a
		
		for (i in 0 .. 10) {
			if(i == 0) continue  // i = 1 로 다시 되풀이 
			a++
			if(i > 0) break	// 종료 
		}
		
		println a 
		
	}
}


소스상으로 for 문과 while 문이 나왔는데, 반복문은 바로 아래에서 설명하도록 하겠습니다.


반복문 혹은 범위문



대표적인 반복문인 for 문과 while 문은 java와 다르지 않습니다.
좀 더 축약형의 표기가 가능한데, 이를테면 아래와 같습니다.
def x= 10
while( x < 50 ){
    // do something 
    x++
}

for(i in 1 .. x) {
    // do something 
}

그루비에서는 for문과 while 문 말고, 요소들을 가진 객체들에 대한 iteration 순회를 할 수 있습니다. 또한, 지정된 범위의 요소들을 순회할 수도 있습니다.

package org.gliderwiki.project

class ListPrint {
	public static void main(def args){
		def list = ["김군", "이군", "김양"]
		// using a variable assignment
		list.each{ firstName->
			println "list = " + firstName
		}

		// using the it variable
		list.each{ println it }
	}
}


이 소스에서 List형태의 요소를 순회하기 위해 .each라는 요소 탐색 메서드를 수행하고 있습니다.


package org.gliderwiki.project

class MyList {
	static void main(def args){
		def myList = [1,2,3, "토요일", "내 이름은 ", "Yion"]
		myList.each{println it}		
	}
}


단순히 지정된 값을 찍지만, 객체의 요소를 따로 지정하지 않아도 'it' 구문으로 요소들이 출력됨을 알 수 있습니다.


package org.gliderwiki.project

class MyRanges {

	static void main(def args){
		def myRanges = 1..10
		myRanges.each{
			println "print range = " + it
		}
		
		println myRanges.from
		println myRanges.to
		println myRanges.getClass().getName()
	}	
}


1부터 10까지 범위를 가지는 변수를 선언하여 그 변수의 범위를 탐색하는 소스입니다.
이 범위 구문은 form 과 to 로 시작 변수의 값, 종료 변수의 값을 확인할 수 있고, 그루비에서 지원되는 IntRange 타입의 객체임을 확인 할 수 있습니다.

출력 결과는 아래와 같습니다.

결과
print range = 1
print range = 2
print range = 3
print range = 4
print range = 5
print range = 6
print range = 7
print range = 8
print range = 9
print range = 10
1
10
groovy.lang.IntRange



이런 범위를 갖는 객체는 좀 더 로직을 편하고 직관적으로 살펴볼 수 있게 합니다. 또한 데이터의 테스트에 대해서 쉬운 방법을 제공하게 될 것입니다.

아래는 좀 더 다양한 형태의 범위 구문과 요소의 탐색에 대한 예제 입니다.
package org.gliderwiki.project

/**
 * Each of these examples print the numbers 0 to 9.
   Using a range with the each operator
 * @author yion
 *
 */
class SimpleLoop {
	
	public static void main(args){
		(0..<10).each {
			println "from 0 to 10 : " + it
		}
		
		10.times {
			println "10 times : " + it
		}
		
		0.upto(9) {
			println "0 up to 9 : " + it
		}
		
		9.downto(0) {
			println "9 down to 0 : " + it
		}
		
		def i = 0
		while (i < 10) {
			println "while i++ : " + i
			i++
		}
	
		for(x in 0..9) {
			println "for x in 0 to 9 : " +x
		}
		
		0.step(100, 10) {
			println "step 10 : " + it
		}
		
	}
}


실행해보면 아래와 같은 결과가 나옵니다.
실행결과
from 0 to 10 : 0
from 0 to 10 : 1
from 0 to 10 : 2
from 0 to 10 : 3
from 0 to 10 : 4
from 0 to 10 : 5
from 0 to 10 : 6
from 0 to 10 : 7
from 0 to 10 : 8
from 0 to 10 : 9
10 times : 0
10 times : 1
10 times : 2
10 times : 3
10 times : 4
10 times : 5
10 times : 6
10 times : 7
10 times : 8
10 times : 9
0 up to 9 : 0
0 up to 9 : 1
0 up to 9 : 2
0 up to 9 : 3
0 up to 9 : 4
0 up to 9 : 5
0 up to 9 : 6
0 up to 9 : 7
0 up to 9 : 8
0 up to 9 : 9
9 down to 0 : 9
9 down to 0 : 8
9 down to 0 : 7
9 down to 0 : 6
9 down to 0 : 5
9 down to 0 : 4
9 down to 0 : 3
9 down to 0 : 2
9 down to 0 : 1
9 down to 0 : 0
while i++ : 0
while i++ : 1
while i++ : 2
while i++ : 3
while i++ : 4
while i++ : 5
while i++ : 6
while i++ : 7
while i++ : 8
while i++ : 9
for x in 0 to 9 : 0
for x in 0 to 9 : 1
for x in 0 to 9 : 2
for x in 0 to 9 : 3
for x in 0 to 9 : 4
for x in 0 to 9 : 5
for x in 0 to 9 : 6
for x in 0 to 9 : 7
for x in 0 to 9 : 8
for x in 0 to 9 : 9
step 10 : 0
step 10 : 10
step 10 : 20
step 10 : 30
step 10 : 40
step 10 : 50
step 10 : 60
step 10 : 70
step 10 : 80
step 10 : 90



for문, while문 등의 익숙한 반복문과 더불어 다양하게 표현이 가능한 범위문에 대해서 이해하는것은 어렵지 않을 것 입니다.

package org.gliderwiki.project

class UpDownTimes {
	public static void main(args){
		5.times {println "Times + $it "}
		1.upto(3) {println "Up + $it "}
		4.downto(1) {println "Down + $it "}
		def sum = 0
		1.upto(100) { sum += 1 }
		println "1.upto(100) = " + sum
		(1..6).each {print "Range $it n"}
	}
}



실행해보면 아래와 같은 결과가 나옵니다.

실행결과
Times + 0
Times + 1
Times + 2
Times + 3
Times + 4
Up + 1
Up + 2
Up + 3
Down + 4
Down + 3
Down + 2
Down + 1
1.upto(100) = 100
Range 1
Range 2
Range 3
Range 4
Range 5
Range 6


이것으로써 제어문과 반복문은 정리하고, 그루비의 클로저에 대해서 알아보도록 하겠습니다.