Groovy - 문법 (Java 와 비교해서 다른 점 위주로)

Language/Groovy 2016. 9. 5. 11:39

생략 가능한 구문들

Import Statements

그루비는 기본적으로 다음 패키지들을 임포트하고 있기 때문에, 다음 패키지들에 대해서는 임포트문을 생략할 수 있다.

● Groovy.lang.*

● Groovy.util.*

● Java.lang.*

● Java.util.*

● Java.net.*

● Java.io.*

● Java.math.BigInteger

● Java.math.BigDecimal

Semicolons

그루비에서 세미콜론은 필수가 아니기 때문에 생략 가능하다. 다음 두 문장 모두 유효하다.

1
2
println 'Hello World';
println 'Hello World'

하지만 두 문장을 한 라인에 코딩할 경우라면 세미콜론으로 각 문장을 구분해 줘야 한다.

1
println 'Hello'; println 'world'

Parentheses

그루비에서 괄호는 필수가 아니기 때문에 생략가능하다. 다음 두 문장은 모두 유효하다

1
2
println ('Hello World')
println 'Hello World'

하지만 간단한 테스트 코드가 아니라면 괄호를 써주는 편이 읽기에 좋다.

Return Type and the return Keyword

그루비에서는 리턴 타입을 명시할 필요도 없고, 메소드 마지막 줄에서 리턴 키워드를 사용할 필요도 없다. 리턴 타입으로 def 키워드를 사용하면 그루비가 알아서 타입을 결정해 준다.

1
2
3
4
5
6
def getPi() {
    3.14
}
 
assert getPi() in BigDecimal
assert getPi() == 3.14

Getters and Setters

그루비는 더 간단한 문법을 지원하기 위해 JavaBeans 와 유사한 GroovyBeans 를 도입했다.

GroovyBeans 내의 프로퍼티들은 public 필드와 유사하므로 getter 와 setter 를 명시적으로 정의할 필요가 없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
    String firstName
    String lastName
 
    def getName() {
        firstName + ' ' + lastName
    }
 
    static void main(args) {
        def person = new Person()
        person.firstName = 'Kwan Young'
        person.lastName = 'Shin'
        assert person.firstName == 'Kwan Young'
        assert person.lastName == 'Shin'
        println person.getName()
    }
}

Access Modifiers

자바에서 접근 제어자를 생략할 경우 해당 패키지내에서만 접근가능도록 설정되지만 그루비에서 생략할 경우에는 기본 접근자가 public 으로 인식되므로 모든 곳에서 접근이 가능하다.  

Checked Exceptions

자바에서는 IOException 과 같은 Checked 예외를 처리하기 위해서 try/catch 문으로 감싸줘야 했지만 그루비에서는 Checked 예외들이 RunTimeException 으로 감싸지므로 try/catch 문을 적용할 필요가 없어졌다.

추가되거나 강화된 문법들

Assertions

그루비는 강력한 assert 키워드를 제공한다.

1
2
3
4
5
6
7
8
9
x=1
assert x
assert (x ==1)
assert ['a'] // 리스트가 비어있지 않으므로 true
assert ['a':1] // 맵이 비어있지 않으므로 true
assert 'a' // 스트링이  비어있지 않으므로 true
assert 1
assert !null
assert true

Closures

재사용 가능한 코드블록인데 파라미터로 사용될 수도 있고 실행시킬 수도 있다. 클로져는 다음과 같이 정의한다.

{arg1, arg2...-> statements}

"->" 는 클로져의 파라미터 목록과 클로저의 기능을 정의하는 블락을 구분해주는 역할을 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
def clos1 = {println "hello world!"}
clos1()
 
def clos2 = {arg1, arg2 -> println arg1+arg2}
clos2(3,4)
 
def method1(book) {
    def prefix = "The title of the book is"
    return {println prefix + book}
}
 
def clos3 = method1("Groovy")
clos3()

클로져는 보통 변수에 할당되고, 이 변수를 사용해서 클로져를 호출한다. 클로져를 파라미터로 받는 메소드도 작성 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Employee {
    def salary
    double calculateRaise(c) {
        return c(salary)
    }
}
 
Employee employee1 = new Employee(salary:1000)
def raise1 = {salary -> (salary * 1.5)}
assert employee1.calculateRaise(raise1) == 1500
 
Employee employee2 = new Employee(salary:500)
def raise2 = {salary -> (salary + 300)}
assert employee2.calculateRaise(raise2) == 800

Collective Data Types

Lists

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
31
32
def x = [1, 2, 3, 4]
 
def y = ['Hi', 1, true, File]
 
def a = []
a += [1,2,3]
assert a == [1,2,3]
assert a.size == 3
// 리스트 에 4와 5를 다음과 같이 추가할 수도 있다.
a << 4 << 5
assert a == [1,2,3,4,5]
a.add(6)
assert a == [1,2,3,4,5,6]
 
assert a[0] == 1
assert a.get(0) == 1
assert a.getAt(0) == 1
assert a[-1] == 6
 
a.putAt(1,1)
assert a == [1,1,3,4,5,6]
// set 메소드는 이전 값을 리턴한다.
assert a.set(1,2) == 1
assert a == [1,2,3,4,5,6]
 
a.each{println "$it"}
a.eachWithIndex{it, index -> println item : "$it", index : "$index"}
 
a -=1
assert a == [2,3,4,5,6]
a = a.minus([2,3,4])
assert a == [5,6]

Maps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def map = ['name':'Bashar', 'age':26, skills:['Java', 'Groovy'], 'author':true]
assert map.size() == 4
 
map += ['city':'Tucson']
assert map == ['name':'Bashar', 'age':26, skills:['Java', 'Groovy'], 'author':true, 'city':'Tucson']
 
map['state'] = 'AZ'
assert map == ['name':'Bashar', 'age':26, skills:['Java', 'Groovy'], 'author':true, 'city':'Tucson', 'state':'AZ']
 
assert map.city == 'Tucson'
assert map['city'] == 'Tucson'
assert map.get('city') == 'Tucson'
assert map.getAt('city') == 'Tucson'
assert map.skills[0] =='Java'
 
assert ['name':'Bashar', 'name':'Abdul'] == ['name':'Abdul']
 
map.each{ it -> println it.key + ":" + it.value}
map.eachWithIndex{it, index -> println "item $index - " + it.key + ":" + it.value}

Ranges

1
2
3
4
5
6
7
8
9
10
11
12
def range = 1..10
assert range == [1,2,3,4,5,6,7,8,9,10]
range = 'a'..'c'
assert range == ['a', 'b', 'c']
 
range = 1..<8
assert range == [1,2,3,4,5,6,7]
 
(1..5).each{println it}
 
assert[*1..4] == [1,2,3,4]
assert[1,*2..4] == [1,2,3,4]

새로운 헬퍼, 라이브러리, ,API 들

GDK

GDK 는 JDK 클래스의 기본 기능에 그루비 만의 기능을 추가한 것이다. 예를 들어 그루비는 JDK의 java.lang.Object, java.lang.Number, java.io.File 클래스등에 다음과 같은 함수를 추가했다.

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
31
32
33
34
// java.lang.Object
def a = [1,2,3]
assert a.any{it > 2} // At least one element satisfies the condition
assert a.every(it > 0) // All elements must satisfy the condition
 
assert a.collect{it * 2} == [2,4,6]
assert a.findAll{it > 2} == [3]
a.print(a)
 
//java.lang.Number
def x = 10;
assert a.abs() == 10
assert x.compareTo(3) == 1
assert x.div(2) == 5
def total = 0
x.downto(5) {
    number -> total += number} // Sums the numbers from 10 to 5 inclusive
assert total == 45
total = 0
x.upto(15) {
    number -> total += number} // Sums the numbers from 10 to 15 inclusive
assert total == 75
 
//java.io.File
def f = new File("C:\\temp\\groovy.txt") // Marks a file for creation
f.text = "Groovy rocks!" // File will be created if it doesn't exist
assert f.exists()
assert f.text == "Groovy rocks!"
f.append("Doesn't?")
assert f.text == "Groovy rocks!?Doesn't?"
f.renameTo(new File("C:\\temp\\groovyRenamed.txt"))
assert f.name == "groovy.txt"
[new File("C:\\temp\\groovy.txt"), new File("C:\\temp\\groovyRenamed.txt")]
.each{it.delete()}

Strings and GStrings

그루비는 JDK의 java.lang.String 타입과 GDK의 groovy.lang.GString 이라는 두가지 타입의 스트링을 지원한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 홑따옴표로 선언한 스트링은 GString 를 지원하지 않고
// 자바에서 스트링을 선언한 것과 같다고 보면 된다.
def text1 = 'Welcom to Groovy'
assert text1 as java.lang.String
 
// 쌍타옴표로 선언한 스트링은 GString 타입 스트링이다.
// 따라서 PlaceHolder 등을 지원한다. 여기서는 $language 가 PlaceHolder 임
def language = "Groovy"
def text2 = "Welcome to $language"
assert text2 == "Welcome to Groovy"
assert text2 as groovy.lang.GString
 
// 3개 따옴표는 각 라인의 마지막에 캐리지 리턴이 추가된다.
def text3 = '''
Welcome to Groovy
-----------------
'''
assert text3 == "\nWelcome to Groovy\n-----------------\n"

GDK 는 다음과 같이 string 관련 추가 메소드를 많이 제공한다.

1
2
3
4
5
6
7
8
9
10
11
def text = "Welcome to Groovy"
assert text.size() && text.length() == 17
assert text.substring(0, 7) == "Welcome"
assert text.contains("Welcome")
assert text.count("Welcome") == 1
text += "\nWhat a great language"
assert text.isNumber() == false
 
assert text.reverse() == "egaugnal taerg a tahW\nyvoorG ot emocleW"
assert text.findAll(){it > 'w'} == ['y']
assert text.replace('Groovy', 'Java') == 'Welcome to Java\nWhat a great language'

Regular Expressions

그루비에서 정규표현식은 슬래쉬 구문으로 정의할 수 있다.

1
2
3
4
5
def pattern = /abc/
assert pattern == 'abc'
 
pattern = /\s\d/
assert pattern == '\\s\\d'

그루비는 정규표현식과 함께 사용할 수 있는 3가지 연산자를 제공한다.

● ~ : 정규표현식을 정의할 때 사용함

● =~ : 정규표현식을 기반으로 검색을 수행함

● ==~ : 정규표현식을 기반으로 일치여부를 반환함

1
2
3
4
5
6
7
8
9
text = "Information technology revolution"
pattern = /\b\w*ion\b/
assert text =~ pattern
def matched = []
text.eachMatch(pattern) {match -> mached += match[0]}
println matched
assert matched.size() == 2
assert matched[0] == "Information"
assert matched[1] == "revolution"

기타

Optional Typing

그루비에서는 변수 선언시에 정적 또는 동적 타이핑이 가능하다. 변수 선언시에 java 처럼 변수 타입을 명시하는 방법을 정적 타이핑이라 하고 def 키워드를 사용해 선언하는 방식을 동적 타이핑이라고 한다. 동적 타이핑의 경우 런타임시에 그루비가 해당 변수의 타입을 결정한다.

Operator Overloading

그루비에서 모든 연산자는 메소드 호출로 해석된다. 예를 들어 1+1 은 1.plus(1) 이라는 식으로 해석되는 것이다. 따라서 이런 메소드를 오버로드하면 연산자도 함께 오버할 수 있다.


출처 - http://springsource.tistory.com/85

'Language > Groovy' 카테고리의 다른 글

Metaprogramming  (0) 2016.09.09
그루비의 동적 객체지향 - 1  (0) 2016.09.09
그루비의 동적 객체지향 - 2  (0) 2016.09.08
What does .delegate mean in groovy?  (0) 2016.09.08
ExpandoMetaClass  (0) 2016.09.08
: