Program Club

Groovy의 숨겨진 기능?

proclub 2020. 10. 10. 12:29
반응형

Groovy의 숨겨진 기능?


이 스레드에서 Groovy가 잊혀진 것 같아서 Groovy에 대해 동일한 질문을 할 것입니다.

  • Groovy 코어에 대한 답변을 제한하십시오.
  • 답변 당 하나의 기능
  • 문서에 대한 링크뿐만 아니라 기능의 예와 간단한 설명을 제공합니다.
  • 첫 번째 줄로 굵은 제목을 사용하여 지형지 물에 레이블 지정

또한보십시오:

  1. Python의 숨겨진 기능
  2. Ruby의 숨겨진 기능
  3. Perl의 숨겨진 기능
  4. 자바의 숨겨진 기능

스프레드 도트 연산자 사용

def animals = ['ant', 'buffalo', 'canary', 'dog']
assert animals.size() == 4
assert animals*.size() == [3, 7, 6, 3]

이 바로 가기입니다 animals.collect { it.size() }.


방법은이를 끌 수 있습니다 :

 myObj1.setValue(10)
 otherObj.setTitle(myObj1.getName())
 myObj1.setMode(Obj1.MODE_NORMAL)

이것으로

 myObj1.with {
    value = 10
    otherObj.title = name
    mode = MODE_NORMAL
 }

해시를 의사 객체로 사용.

def x = [foo:1, bar:{-> println "Hello, world!"}]
x.foo
x.bar()

오리 타이핑과 결합하면이 접근 방식으로 먼 길을 갈 수 있습니다. "as"연산자를 쓸 필요도 없습니다.


엘비스 에 대해 아는 사람 있나요?

def d = "hello";
def obj = null;

def obj2 = obj ?: d;   // sets obj2 to default
obj = "world"

def obj3 = obj ?: d;  // sets obj3 to obj (since it's non-null)

객체에 어떤 메소드가 있는지 알아내는 것은 metaClass에 요청하는 것만 큼 쉽습니다.

"foo".metaClass.methods.name.sort().unique()

인쇄물:

["charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo",
 "compareToIgnoreCase", "concat", "contains", "contentEquals", "copyValueOf", 
 "endsWith", "equals", "equalsIgnoreCase", "format", "getBytes", "getChars", 
 "getClass", "hashCode", "indexOf", "intern", "lastIndexOf", "length", "matches", 
 "notify", "notifyAll", "offsetByCodePoints", "regionMatches", "replace", 
 "replaceAll", "replaceFirst", "split", "startsWith", "subSequence", "substring", 
 "toCharArray", "toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "wait"]

누락 된 정적 메서드를 가로 채려면 다음을 사용하십시오.

 Foo {
    static A() { println "I'm A"}

     static $static_methodMissing(String name, args) {
        println "Missing static $name"
     }
 }

Foo.A()  //prints "I'm A"
Foo.B()  //prints "Missing static B"

-


구조화

Groovy에서는 다른 이름으로 불릴 수 있습니다. 클로저에서 구조화라고합니다. 얼마나 편리 할 수 ​​있는지 결코 믿지 못할 것입니다.

def list = [1, 'bla', false]
def (num, str, bool) = list
assert num == 1
assert str == 'bla'
assert !bool

groovy로 자바 코드를 테스트 할 때 객체 그래프 빌더는 놀랍습니다.

def company = builder.company( name: 'ACME' ) {
   address( id: 'a1', line1: '123 Groovy Rd', zip: 12345, state: 'JV' )
   employee(  name: 'Duke', employeeId: 1 ){
      address( refId: 'a1' )
   }
}

표준 기능이지만 여전히 정말 좋습니다.

ObjectGraphBuilder

( 빌더 지원이 작동하는 List대신 빈 목록의 기본값 인 POJO의 특성을 제공해야합니다 null.)


println 
"""
Groovy has "multi-line" strings.
Hooray!
"""

Groovy 1.6에서 정규 표현식은 모든 클로저 반복자 (각각, 수집, 주입 등)와 함께 작동하며 캡처 그룹으로 쉽게 작업 할 수 있습니다.

def filePaths = """
/tmp/file.txt
/usr/bin/dummy.txt
"""

assert (filePaths =~ /(.*)\/(.*)/).collect { full, path, file -> 
        "$file -> $path"
    } ==  ["file.txt -> /tmp", "dummy.txt -> /usr/bin"]

Java와 달리 Groovy에서는 기본 유형뿐만 아니라 모든 것이 switch 문에 사용될 수 있습니다 . 일반적인 eventPerformed 메서드에서

switch(event.source) {
   case object1:
        // do something
        break
   case object2:
        // do something
        break
}

우주선 연산자 사용

모든 종류의 사용자 지정 정렬 시나리오에 유용한 우주선 연산자를 좋아합니다 . 몇 가지 사용 예가 여기에 있습니다 . 특히 도움이되는 한 가지 상황은 여러 필드를 사용하여 개체의 즉석에서 비교기를 만드는 것입니다. 예 :

def list = [
    [ id:0, first: 'Michael', last: 'Smith', age: 23 ],
    [ id:1, first: 'John', last: 'Smith', age: 30 ],
    [ id:2, first: 'Michael', last: 'Smith', age: 15 ],    
    [ id:3, first: 'Michael', last: 'Jones', age: 15 ],   
]

// sort list by last name, then first name, then by descending age
assert (list.sort { a,b -> a.last <=> b.last ?: a.first <=> b.first ?: b.age <=> a.age })*.id == [ 3,1,0,2 ]

클로저는 리소스 관리의 모든 오래된 트라이-파이널 게임을 없앨 수 있습니다. 파일 스트림은 블록 끝에서 자동으로 닫힙니다.

new File("/etc/profile").withReader { r ->
    System.out << r
}

다음 groovy.transform과 같은 GDK 패키지 내부의 변환에서 제공하는 기능 :

  • @Immutable: @Immutable 주석은 정의 된 속성으로 불변 클래스를 만들 때 일반적으로 작성되는 필요한 getter, 생성자, equals, hashCode 및 기타 도우미 메서드를 추가하는 AST 변환을 실행하도록 컴파일러에 지시합니다.
  • @CompileStatic: 이렇게하면 Groovy 컴파일러가 Java 스타일의 컴파일 시간 검사를 사용한 다음 정적 컴파일을 수행하여 Groovy 메타 개체 프로토콜을 우회 할 수 있습니다.
  • @Canonical: @Canonical 주석은 컴파일러에게 위치 생성자, 같음, 해시 코드 및 예쁜 인쇄 toString을 클래스에 추가하는 AST 변환을 실행하도록 지시합니다.

기타 :

  • @Slf4j이 로컬 변환은 LogBack 로깅을 사용하여 프로그램에 로깅 기능을 추가합니다. log라는 이름의 바인딩되지 않은 변수에 대한 모든 메서드 호출은 로거 호출에 매핑됩니다.
  • Groovy의 XML Slurper : XML의 손쉬운 파싱. 킬러 기능!

toSpreadMap ()을 사용하여 목록을 맵으로 변환 할 수 있습니다. 이는 목록의 순서가 키와 연관된 값을 결정하기에 충분할 때 편리합니다. 아래 예를 참조하십시오.

def list = ['key', 'value', 'foo', 'bar'] as Object[]
def map = list.toSpreadMap()

assert 2 == map.size()
assert 'value' == map.key
assert 'bar' == map['foo']

클로저 기반 인터페이스 구현

다음과 같이 입력 된 참조가있는 경우 :

MyInterface foo

다음을 사용하여 전체 인터페이스를 구현할 수 있습니다.

foo = {Object[] args -> println "This closure will be called by ALL methods"} as MyInterface

또는 각 메서드를 개별적으로 구현하려는 경우 다음을 사용할 수 있습니다.

foo = [bar: {-> println "bar invoked"}, 
    baz: {param1 -> println "baz invoked with param $param1"}] as MyInterface

null목록에서 값 제거

def list = [obj1, obj2, null, obj4, null, obj6]
list -= null
assert list == [obj1, obj2, obj4, obj6]

내가 조금 늦었다는 것을 알고 있지만 여기에 몇 가지 멋진 기능이 누락 된 것 같습니다.

컬렉션 플러스 / 마이너스 연산자

def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9)
assert l == [1, 4, 6, 7, 8, 9]

def m = [a: 1, b: 2] + [c: 3] - [a: 1]
assert m == [b: 2, c: 3]

Switch 문

switch (42) {
  case 0: .. break
  case 1..9: .. break
  case Float: .. break
  case { it % 4 == 0 }: .. break
  case ~/\d+/: .. break
}

범위 및 색인

assert (1..10).step(2) == [1, 3, 5, 7, 9]
assert (1..10)[1, 4..8] == [2, 5, 6, 7, 8, 9]
assert ('a'..'g')[-4..-2] == ['d', 'e', 'f']

유니 코드 변수 이름

def α = 123
def β = 456
def Ω = α * β
assert Ω == 56088

@대리자

class Foo {
    def footest() { return "footest"}   
}

class Bar {
    @Delegate Foo foo = new Foo()     
}

def bar = new Bar()

assert "footest" == bar.footest()

리터럴의 밑줄

긴 리터럴 숫자를 쓸 때, 예를 들어 수천 개의 단어 그룹과 같이 일부 숫자가 함께 그룹화되는 방식을 파악하기가 더 어렵습니다. 숫자 리터럴에 밑줄을 넣을 수있게함으로써 이러한 그룹을 쉽게 찾을 수 있습니다.

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010

암시 적 인수를 사용한 인수 재정렬은 또 다른 좋은 방법입니다.

이 코드 :

def foo(Map m=[:], String msg, int val, Closure c={}) {
  [...]
}

다음과 같은 모든 방법을 만듭니다.

foo("msg", 2, x:1, y:2)
foo(x:1, y:2, "blah", 2)
foo("blah", x:1, 2, y:2) { [...] }
foo("blah", 2) { [...] }

그리고 더. 명명 된 인수와 서수 인수를 잘못된 순서 / 위치로 배치하여 망칠 수 없습니다.

물론 "foo"의 정의에서 "String msg"및 "int val"에서 "String"및 "int"를 생략 할 수 있습니다. 명확성을 위해 그대로 두었습니다.


매개 변수 및 매개 변수 기본값 값으로 폐쇄의 조합이라고 생각합니다.

public void buyItems(Collection list, Closure except={it > 0}){
  list.findAll(){except(it)}.each(){print it}
}
buyItems([1,2,3]){it > 2}
buyItems([0,1,2])

인쇄 : "312"


메서드 매개 변수에서 확산 연산자 사용

이것은 코드를 데이터로 변환 할 때 큰 도움이됩니다.

def exec(operand1,operand2,Closure op) {
    op.call(operand1,operand2)
}

def addition = {a,b->a+b}
def multiplication = {a,b->a*b}

def instructions = [
     [1,2,addition],
     [2,2,multiplication]
]

instructions.each{instr->
    println exec(*instr)
}

이 사용법도 도움이됩니다.

String locale="en_GB"

//this invokes new Locale('en','GB')
def enGB=new Locale(*locale.split('_'))

메모 화

Memoization은 값 비싼 함수 호출의 결과를 저장하고 동일한 인수로 함수가 다시 호출 될 때마다 캐시 된 결과를 반환하는 최적화 기술입니다.

무제한 버전이 있는데, 그것은 그것이 볼 수있는 (입력 인수, 반환 값) 쌍을 캐시합니다. LRU 캐시를 사용하여 마지막으로 본 N 개의 입력 인수와 그 결과를 캐시하는 제한된 버전.

방법의 기억 :

import groovy.transform.Memoized

@Memoized
Number factorial(Number n) {
    n == 0 ? 1 : factorial(n - 1)
}

@Memoized(maxCacheSize=1000)
Map fooDetails(Foo foo) {
    // call expensive service here
}

폐쇄 메모 :

def factorial = {Number n ->
    n == 0 ? 1 : factorial(n - 1)
}.memoize()

fooDetails = {Foo foo ->
    // call expensive service here
}.memoizeAtMost(1000)

Wikipedia 페이지 에는 컴퓨터 과학에서 Memoization 사용에 대한 광범위한 정보가 있습니다. 나는 단지 하나의 간단한 실용적인 사용을 지적 할 것이다.

상수 초기화를 가능한 마지막 순간으로 연기

Sometimes you have a constant value that cannot be initialized at class definition or creation time. For example, the constant expression may make use of another constant or a method from a different class, which will be plugged in by something else (Spring or such) after the initialization of your class.

In this case, you can convert your constant into a getter and decorate it with @Memoized. It will only be computed once, the first time it's accessed, and then the value cached and reused:

import groovy.transform.Memoized

@Memoized
def getMY_CONSTANT() {
    // compute the constant value using any external services needed
}

Groovy can work a lot like Javascript. You can have private vars and functions via closure. You can also curry functions with closures.

class FunctionTests {

def privateAccessWithClosure = {

    def privVar = 'foo'

    def privateFunc = { x -> println "${privVar} ${x}"}

    return {x -> privateFunc(x) } 
}


def addTogether = { x, y ->
    return x + y
}

def curryAdd = { x ->
    return { y-> addTogether(x,y)}
}

public static void main(String[] args) {
    def test = new FunctionTests()

    test.privateAccessWithClosure()('bar')

    def curried = test.curryAdd(5)

    println curried(5)
}
}

output:

foo bar 10


Dynamic method invocation

You can invoke a method using a string with its name

class Dynamic {
    def one() { println "method one()" }
    def two() { println "method two()" }
}

def callMethod( obj, methodName ) {
    obj."$methodName"()
}

def dyn = new Dynamic()

callMethod( dyn, "one" )               //prints 'method one()'
callMethod( dyn, "two" )               //prints 'method two()'
dyn."one"()                            //prints 'method one()'

How to build a JSON tree in a couple of lines in groovy ?

1) define your tree with self-referential withDefault closure

def tree // declare  first before using a self reference
tree = { ->  [:].withDefault{ tree() } }

2) Create your own JSON tree

frameworks = tree()
frameworks.grails.language.name = 'groovy'
frameworks.node.language.name = 'js'

def result =  new groovy.json.JsonBuilder(frameworks)

Which gives: {"grails":{"language":{"name":"groovy"}},"node":{"language":{"name":"js"}}}


Safe navigation operator

The Safe Navigation operator is used to avoid a NullPointerException. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception, like so:

def person = Person.find { it.id == 123 }        // find will return a null instance    
def name = person?.name                          // use of the null-safe operator prevents from a NullPointerException, result is null

Multiple variables deceleration

1)Multiple variables declarations in single line

def (a,b,c) = [1,2,3]

2)Using different type declarations.

def (String a, int b) = ['Groovy', 1]

Coercion operator

The coercion operator (as) is a variant of casting. Coercion converts object from one type to another without them being compatible for assignment. Let’s take an example:

Integer x = 123
String s = (String) x
Integer is not assignable to a String, so it will produce a ClassCastException at runtime This can be fixed by using coercion instead:

Integer x = 123 String s = x as String
Integer is not assignable to a String, but use of as will coerce it to a String

참고URL : https://stackoverflow.com/questions/303512/hidden-features-of-groovy

반응형