0,0
рейтинг
18 июня 2011 в 05:31

Разработка → Groovy за 15 минут – краткий обзор

Java*
Groovy — объектно-ориентированный язык программирования разработанный для платформы Java как альтернатива языку Java с возможностями Python, Ruby и Smalltalk.

Groovy использует Java-подобный синтаксис с динамической компиляцией в JVM байт-код и напрямую работает с другим Java кодом и библиотеками. Язык может использоваться в любом Java проекте или как скриптовый язык.

Возможности Groovy (отличающие его от Java):

— Статическая и динамическая типизация
— Встроенный синтаксис для списков, ассоциативных массивов, массивов и регулярных выражений
— Замыкания
— Перегрузка операций

[http://ru.wikipedia.org/wiki/Groovy]

Более того, почти всегда java-код — это валидный groovy-код.


Установка


Для установки нужно скачать архив с оф. сайта , распаковать его в удобное место и добавить переменyю окружения GROOVY_HOME, и добавить путь до groovy/bin в PATH:
export GROOVY_HOME=~/path/to/groovy/
export PATH=$GROOVY_HOME/bin:$PATH


В IDE NetBeans 7.0 поддержка groovy идет из коробки, для IDE Eclipse существует очень хороший плагин, который можно взять здесь.

Groovy


Самое главное отличие от java: в Groovy всё является объектами. Все примитивные типы сразу же упаковываются в объекты. Т.е. «int x» на самом деле является «Integer x»

println 1.class
int a = 10
println a.class


class java.lang.Integer
class java.lang.Integer


Следует не забывать о том, что все упаковочные типы — неизменяемые, поэтому каждый раз при каком-либо вычислении будет создаваться новый объект.

Строки в Groovy


1) Java Strings — строки в одинарных кавычках
2) Groovy Strings, они же GStrings — в обычных кавычках
В строках groovy можно вставлять параметры, в обычные строки — нельзя

javaString = 'java'
groovyString = "${javaString}"
j = '${javaString}' 
bigGroovyString = """
    ${javaString}
    ${groovyString}
    ${j}
    ${2 + 2}
"""

println bigGroovyString

    java
    java
    ${javaString}
    4


К строкам применимы операции + и *
groovy:000> a = "a"
===> a
groovy:000> a + "123"
===> a123
groovy:000> a * 5    
===> aaaaa


Так же к строкам применимы ++ и - — (т.к. в groovy поддерживается перегрузка операторов)
groovy:000> a = 'abc'
===> abc
groovy:000> a++
===> abd
groovy:000> a--
===> abс


В groovy есть поодержка регулярных выражений на уровне конструкций языка:
groovy:000> r =~ '^a$'
===> java.util.regex.Matcher[pattern=^a$ region=0,1 lastmatch=]


Встроенная поддержка maps + lists


Так же на уровне конструкций языка поддерживаются словари (maps) и списки:
groovy:000> a = [1, 3, 5]
===> [1, 3, 5]
groovy:000> b = [1: true, 0: false]
===> {1=true, 0=false}


Ranges


Получать доступ к элементам списков в groovy можно следующим образом:
groovy:000> a = "0123456789"
===> 0123456789
groovy:000> a[1..4]
===> 1234
groovy:000> a[1..-1]
===> 123456789
groovy:000> a[-1..0]
===> 9876543210
groovy:000> a[1..<9]
===> 12345678
groovy:000> a[1, 3, 5]
===> 135
groovy:000> b = 1..5
===> 1..5
groovy:000> a[b]
===> 12345


Range — это такой же объект, поэтому возможны конструции, подобные последней. Отрицательные индексы, как в python, возвращают элементы с конца списка.

Range можно составить из строк:
groovy:000> 'a'..'aa'
===> a..aa


Более того, range можно сделать из любого объекта, у которого есть методы next() и prev().

Циклы


Циклы в groovy точно такие же, как и в java, плюс к ним добавляется еще один «foreach»:
for (i in 0..9) { 
    print i 
}

for (int i = 0; i < 9; ++i) {
    print i
}

for (Integer i : 0..9) { 
    print i 
}


Функции


def functionA(argA) {
    print ArgA
}

int functionB(int argB) {
    print argB
    return argB
}

String fuctionC() {
    "Hello World"
}


Ключевое слово return указывать не обязательно — по умолчанию будет возвращено значение последней упомянутой переменной в фукции.

Closures


Closure — это анонимная функция
def cl = {a, b ->
    println a
    println b
}

cl(1, 2)


У многих объектов есть методы, в качестве параметров которым передаются closure:
1.upto 10, { 
    print it
}

10.times { 
    print it
}


Доступно большое количество методов для обработки последовательностей, к которым можно применять замыкания:

'qwerty'.each {
    print it
}

('a'..'z').each {
    print it
}

('a'..'z').findAll { el -> // = filter
    el in ['e', 'y', 'u', 'i', 'o', 'a']
}.each {
    print it + ' '
}

(0..10).collect { el -> // = map
    el * 10
}.each {
    print it + ' '
}

def sum = (0..10).inject(0) { prev, elem -> // = reduce 
    return prev + elem    
}


В closure так же не обязательно использовать ключевое слово return. Если явно не задано имя параметру, то по умолчанию используется it.

Так как closure является объектом, то ничего не мешает возвращать его из другого closure, и таким образом создавать функции высших порядков:
def cloA = {param ->
    def cloB = {
        return param * 10    
    }
}

def b = cloA(10)
println b(10)


Файлы



Для директорий есть функции eachFile и eachFileRecursive:

new File('.').eachFile {
    println it
}

./.project
./src
./.settings
./.classpath
./bin


Для обработки текстовых файлов — функция eachLine:
new File('textfile.txt').eachLine {
    println it
}


Писать в файлы так же очень удобно:
def pw = new File('textfile.txt').newPrintWriter()
pw.println("new line")


Классы


class Account {
    String name
    BigDecimal value
}

// конструктор по умолчанию добавляется автоматически
// такой конструктор - синтаксический сахар для 
// a = new Account()
// a.setName("Account #1")
// a.setValue(new BigDecimal(10))
a = new Account(name : "Account #1", value : new BigDecimal(10))

// геттеры и сеттеры генерируются автоматически
def name = a.getName()
a.setName("Account #2")
println "${a.name}"

class Person {
    def first
    def last

    // явно задаем сеттер
    void setFirst(first) {
        println "${this.first} is becoming ${first}"
        this.first = first
    }
}

p = new Person(first : "A", last : "G")
// если обращаться к полю, то будет использоваться сеттер
p.first = "C"

println "${p.first} ${p.last}"

// наследвание как в java
class ExtendedAccount extends Account {
    def debt
    
    // задаем конструктор
    ExtendedAccount(name, value, debt) {
        setName(name)
        setValue(value)
        setDebt(debt)
    }
    
    def String toString() {
        "${name} ${value} ${debt}"
    }
}

// тут будет ошибка "Could not find matching constructor for: ExtendedAccount()"
//e = new ExtendedAccount()

println new ExtendedAccount("A", new BigDecimal(10), 1)


Неизменяемые классы задаются с помощью аннотации Immutable:

@Immutable
class ImmutableClass {
    String a
    Integer b
}

def ic = new ImmutableClass(a : "a", b : 1)


При использовании этой аннотации нужно явно указывать, какого типа данных поле.

Операторы



"?:" Elvis operator
def b = a ?: "b"

Проверяет переменную a, и если в ней null или false, то берет указанное следом значение. Иначе берется значение переменной a.

"?." Safe navigation
Используется для избежания ошибки NullPointerException
def user = Users.get("a")
def posts = user?.posts
println posts 

Вернет null, если если в user содержится null вместо того, чтобы бросать NullPointerException.

"*." Spread operator
Применяет указанный метод для всех элементов какой-либо коллекции. Эквивалент следующему:
parent*.action == parent.collect {ch -> child?.action}


Пример использования:
def sizes = ['string', 'long string']*.size()
println sizes

[6, 11]


Так же монжо использовать для составления списков и словарей:
def x = [2, 3]
def y = [0, 1, *x, 4]
println y

def a = [3 : 'c', 4 : 'd']
def b = [1 : 'a', 2: 'b', * : a, 5 : 'e']
println b

[0, 1, 2, 3, 4]
[1:a, 2:b, 3:c, 4:d, 5:e]


В Groovy можно перегружать операторы +, -, * и т.п. Для этого нужно определить соотвествующий метод для класса. Например, для перегрузки оператора ++ нужно переопределить метод next():

class RandomVal {
    // для этого поля не будут сгенерированы сеттеры и геттеры
    private def value
    private Random randomGen = new Random()
    
    def next() {
        this.value = randomGen.nextInt()
    }
    
    RandomVal() {
        this.value = randomGen.nextInt()
    }
    
    def String toString() {
        "${this.value}"
    }
}

def r = new RandomVal()
println(r)
r++
println(r)


Оператор "==" уже перегружен для всех объектов — и вызывает метод «isEquals()». Полный список методов, которые нужно переопределить для перегрузки операторов, доступен здесь: http://groovy.codehaus.org/Operator+Overloading.

SQL



SQL запросы обрабатываются очень просто:
import groovy.sql.Sql

def final ADDRESS = "jdbc:jtds:sqlserver://serverName/dbName"
def final USERNAME = "username"
def final PASSWD = "password"
def final DRIVER = "net.sourceforge.jtds.jdbc.Driver"
sql = Sql.newInstance(ADDRESS, USERNAME, PASSWD, DRIVER)

sql.eachRow("select * from tableName") { el ->
    println "${el.id} -- ${el.firstName}"
}

def firstName = "A"
def lastName = "G"
sql.execute("insert into tableName (firstName, lastName) " + 
    "values (${firstName}, ${lastName})")

sql.execute("insert into tableName (firstName, lastName) " +
    "values (?, ?)", [firstName, lastName])


XML


В groovy существуют билдеры, которые можно использовать для генерации XML. Для генерации создается экземпляр объекта MarkupBuilder, на котором вызываются псевдо-методы — название этого метода и переданные параметры будет использоваться для генерации тега:

import groovy.xml.MarkupBuilder

def mb = new MarkupBuilder()

mb.html() {
    head() {
        title("This is the title")
    }
    
    body() {
        div("class" : "main") {
            p("this is the body")
        }
    }
}

Вывод:
<html>
  <head>
    <title>This is the title</title>
  </head>
  <body>
    <div class='main'>
      <p>this is the body</p>
    </div>
  </body>
</html>


В качестве параметра конструктору MarkupBuilder можно передавать любой PrintWriter:
def fb = new MarkupBuilder(new File("index.html").newPrintWriter())


Парсинг XML так же очень простой:
import groovy.xml.MarkupBuilder
import java.io.StringWriter

def sw = new StringWriter()
def mb = new MarkupBuilder(sw)

mb.html() {   
    body() {
        div("class" : "main") {
            p("this is the body")
        }
        
        div() {
            p("this is the body 1")
            p("this is the body 2")
            p("this is the body 3")
        }
    }
}

def xml = sw.toString()

println xml

import groovy.util.XmlParser;

def parser = new XmlParser()
def doc = parser.parseText(xml)
//def doc = parser.parse("index.html")

println doc.body.div[1].p[1] // возвращает Node
println doc.body.div[1].p // возвращает список, состоящий из Node
println doc.body.div["@class"] // список значений аттрибута class для всех div


Вывод:
<html>
  <body>
    <div class='main'>
      <p>this is the body</p>
    </div>
    <div>
      <p>this is the body 1</p>
      <p>this is the body 2</p>
      <p>this is the body 3</p>
    </div>
  </body>
</html>
p[attributes={}; value=[this is the body 2]]
[p[attributes={}; value=[this is the body 1]], p[attributes={}; value=[this is the body 2]], 
    p[attributes={}; value=[this is the body 3]]]
[main, null]


Groovlets


С помощью класса GroovyServlet возможно запускать скрипты на Groovy как сервлеты.
В первую очередь, для этого нужно добавить несколько строчек в web.xml:

<servlet>
    <servlet-name>GroovyServlet</servlet-name>
    <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>GroovyServlet</servlet-name>
    <url-pattern>*.groovy</url-pattern>
</servlet-mapping>


Теперь все запросы для файлов .groovy будут обрабатываться классом GroovyServlet.
В этих скриптах уже доступны для использования следующие переменные:

— request & response
— context, application, session
— out (= response.getWriter())
— sout (= response.getOutputStream())
— html (= new MarkupBuilder(out))

html.html() {   
    body() {
        div("class" : "main") {
            p("this is the body")
        }
        
        div() {
            p("this is the body 1")
            p("this is the body 2")
            p("this is the body 3")
        }
    }
}


Отдаст браузеру сгенерированную html-страницу.

Список используемых источников:


Kenneth Barclay, John Savage «Groovy programming: an introduction for Java developers»
http://groovy.codehaus.org/
Алексей Григорьев @alexeygrigorev
карма
40,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (50)

  • –11
    Какая-то помесь питона с жикварей…
    Слышал, что разрабатывают на груви, но не видел ни груви программистов, ни продуктов на груви.
    Расскажите хоть саксес стори какой…
    • +2
      В основном success stories связаны с фреймворком на groovy — на grails.
      А вообще вот — video.google.com/videoplay?docid=-7629776691121323726#
    • +1
      есть модуль goovy под ibm websphere portal, в принципе, оно работает, но…

      штука глючная, изменения в скриптах отслеживает с трудом, бывает что скомпилированый скрипт «залипает», и надо производить танцы с бубнами типа физического перезапуска кластера и смены даты файлов скриптов, чтобы оно их перекомпилило
      вроде в новой версии обещают что починили, но ставить эксперименты на боевой системе не хочется

      штука эта от сторонней компании, фриварная и без обязательств, соответственно ibm ее не суппортит, и если что вдруг легло, то типа разбирайтесь сами

      в общем, пока в корпоративный сегмент им рано, вот лет через 5, как повзрослеют…
      • 0
        Я писал в блоге об этом некоторое время назад — дам поэтому ссылку mantonov.blogspot.com/2011/04/groovy-c-java-production-1.html

        Мы внедряем Groovy достаточно давно в разных частях достаточно крупного (в общей сложности более 3 млн строк Java кода) и достаточно старого проекта на Java, наталкиваемся на некоторые неожиданные сложности и нестыковки, но пока вроде бы получается находить решения.

        • 0
          В целом, я вашу скептичность полностью поддерживаю по поводу внедрения в продакшен. Но оно заслуживает того, чтобы поэкспериментировать.
          • 0
            у нас оно уже в проме, и в целом живет
            при обновлениях регулярно косяки вылазят, но вроде научились с ними бороться
            потому и новую версию движка пока не хочется ставить
    • +6
      Groovy разрабатывается компанией SpringSource(подразделение VMWare) — команда, что разрабатывает Spring, Apache Tomcat, Apache HTTPD, RabbitMQ, Redis, AspectJ и многие другие опенсорсные(и не только) проекты. Groovy-related вещами занимается около 8 человек. Success stories можно почитать на сайте SS.

      Из популярных продуктов — Grails, на Dice.com вакансий по нему больше чем по Tapestry, Wicket, примерно одинаковое с Django & Zend. Очень активный мейл-лист.

      Groovy также популярен как DSL: Gradle & Maven 3 (Build Tools), Geb (Web testing via Selenium Webdriver), Griffon (Java GUI), Spock (BDD/TDD), GPars (Parallelism, Concurrency, Actors..), Play! framework(as a Template Engine). Есть плагины для анализа кода — CodeNarc, опциональное статическое типизирование Groovy++.

      Есть поддержка IDE: SpringSource Tool Suite(бесплатный набор плагинов к Eclipse) & IntelliJ IDEA(Groovy есть даже в бесплатной Community версии), Netbeans + текстовые редакторы.

      Вообщем вполне себе здоровое сообщество — не забываем, что вы можете использовать без проблем Java библиотеки, наследывать Java классы и наоборот (JavaClass extends GroovyClass).
    • 0
      Возможно, это оттого, что некоторые приведенные примеры действитульно не очень удачны, а некоторых интересных примеров нет, а те что есть — немного искусственны.
  • +1
    Можно создать классы на Groovy с аннотациями из hibernate, а затем использовать эти домены в java коде? Нет каких-то подводных камней?

    Для Groovy видел кучу всяких библиотек и фреймворков — есть там что-нибудь интересного, чтобы взяться за голову и сказать — как же я раньше без этого жил? :)
    • +2
      Насчет hibernate не пробовал, но в EJB проектах можно использовать groovy и аннотации — ссылка. Думаю, все будет хорошо работать. Так же при смешивании java и groovy классов лучше придерживаться такого правила: интерфесы писать на java, а реализацию — на groovy. Тогда эти интерфейсы затем можно использовать где угодно, хоть в java, хоть в groovy.

      Насчет взяться за голову — да, есть такое. После python в джаве иногда становится очень грустно… И на помощь приходит groovy.

      И код выразителен. Вот, например, сравните:
      Groovy:
      def query = group.getInstanceOf("/index");
      query.setAttributes(["column": "subject", "table": "emails"])
      


      Java:
      ST query = group.getInstanceOf("/index");
      Map<String, String> atrs = new HashMap<String, String>();
      atrs.put("column", "subject");
      atrs.put("table", "emails");
      query.setAttributes(atrs);
      


      Какой вариант вам больше нравится? :)
      • +3
        В java можно и так:

        query.setAttributes(new HashMap({{
        put(«column», «subject»);
        put(«table», «emails»);
        }}));

        Но синт. сахар меня не возбуждает уже, вышел из этого возраста :) Для меня важнее наличие клёвых библиотек и фреймворков, которые упрощают и ускоряют разработку. Например, в Tapestry 5 и не нужно так делать с параметрами для шаблона. Т.е. не нужно вот этого кода вообще:

        groovy+какой-то веб-фреймворк:
        def query = group.getInstanceOf("/index");
        query.setAttributes([«column»: «subject», «table»: «emails»])

        java+tapestry5:
        пусто :)
        • +1
          Так можно и tapestry использовать в groovy.
          Кстати, не пробовал этот фреймворк, рекомендуете?
          • +2
            Ну да, я поэтоу и думаю не уходить в крайности, а использовать плюсы groovy в java.

            Tapestry 5 рекомендую, если делаете что-то кастомное и оригинальное. Если же нужно сделать, что-то шаблонное, типа блога за 15 минут, то со сторонними компонентами в Tapestry 5 сейчас не очень (значительно хуже, чем с плагинами в Grails).
    • 0
      Я делал так — совершенно спокойно все работает. Единственный подводный камень, с которым я столкнулся: по некоторым причинам я использовал propertyMissing() — перехватчик обращения к несуществующему полю класса для других целей. И когда Hibernate из-за ошибки в маппинге попытался присвоить значение несуществующему полю в классе, результат был совершенно неожиданный, и я довольно долго искал причину.
    • 0
      Для меня очень полезной была поддержка XML-а в Груви. Намного удобнее, чем в Джаве. Но когда я стал разбираться со Скалой, понял, что это все были детские игрушки :)
  • +1
    Очень хорошо написаный обзор языка. Приятно почитать и позволяет хоть слегка, но понимать что написано в коде.
  • +9
    Я обожаю груви. Пишу на нём под фреймвёрк grails. Я даже не знаю, сколько я потратил на его изучение — наверно совсем мало. Просто прочитал getting started и пару статей. Язык невероятно интуитивный и лаконичный.
    Очень много примеров и решений на груви можно найти в разделе groovy goodness вот здесь — mrhaki.blogspot.com/
  • 0
    Хороший обзор, но стоит уточнить, что closures это на самом деле совсем не функции в Groovy, хоть и выглядят как функциии. Это объекты (экземляры Closure), что принципиально отличает их от функций-методов.
    • +1
      Да, в этом плане кстати я рекомендую иногда компилировать простенькие классы на Groovy в байткод, а потом декомпилировать в Java :) Тогда можно видеть, как это все внутри склеивается. Интересно и познавательно.
      • 0
        А чем вы декомпилируете груви?
        У меня через jd-gui нечитабельная фигня получается.
        • 0
          DJ Java Decompiler, jd-gui, cavaj… В принципе там все идет от движка JAD :) с допиливаниями.

          А мусор — мусор будет всегда, естественно, т.к. кодогенератор груви генерит много кода для поддержки метапрограммирования (в частности, роутинг вызовов методов через метаклассы и прочее).

          Но при желании из него можно вытащить интересные вещи. Кому нибудь будет интересен пост о декомпилировании груви? ;)
          • 0
            Мне точно будет )))
  • +3
    Еще нашел интересную ссылку — groovyconsole.appspot.com/
    Веб-интерпретатор groovy
  • 0
    По моему скромному личному мнению scala выглядит как-то попристойнее, мы ее мирили с vaadin фрейворком, все работало, объем кода сокращается в разы.
    • 0
      Тоже смотрю на скалку. Ее можно использовать как скриптовый язык? Хотелось бы разрабатывать не компилируя, а интерпретируя, а сборку уже компилять.
      • 0
        Ну, строго говоря, Groovy тоже никогда не интерпретируется, а всегда предварительно компилирует весь класс (-ы) в байткод. Другое дело, что он может промежуточно создавать .class файлы на диске, подобно javac (используя компилятор groovyc), или загружать код из файлов .groovy, генерить байткод и запускать его на выполнение (через Groovy Script Engine).

        • 0
          Кстати, рекомендую книжку Groovy in Action. 2nd edition. В написании принимали участие авторы и коммитеры языка и рантайма.
          • 0
            Что-то второго издания в сети найти не могу. Покупали книжку эту?
    • 0
      В Groovy есть одно приемущество (хотя, конечно, это можно оспорить) — java код без изменений в 99% случаях будет работать в Groovy. И поэтому учиться groovy для java программиста намного проще. Можно сначала писать как в джаеве, и, постепенно пробуя на вкус все удобства groovy, использовать его больше и больше.
      В скала же синтаксис в большей степени не похож на джаву, поэтому нужно потратить некоторое время на освоение — сразу сесть и начать писать код, постепенно изучая язык лучше, не получится.

      Но, думаю, эти два языка заняли свои ниши и поселились на jvm всерьез и надолго.
  • +8
    Мне так нравиться название Elvis operator если наклонить голову влево то это точно он ?:
  • +2
    Groovy — относительно неплохой язык скриптования для тех кто привык к Java. Это по сути немного syntax suggar которые так не хватает яве.

    Но дается с очень большой ценой — производительность груви в среднем раз в 10 меньше чем явы и не важно байт код это или режим скрипта — все дело в мета программирование и количестве оберток которые нужно дернуть прежде чем добраться до реального метода.

    Если говорить о Grails то его проблема в количестве зависимостей от сторонних библиотек, так что если понадобится добавить свою зависимость есть большая вероятность что она будет несовместима.

    В общем лично я предпочитаю python и scala. Хотя возможно все началось c groovy.
    • 0
      Ну строго говоря, опять же, Groovy не имеет режима скрипта, если вы подразумеваете под этим чистую интерпретацию. Он всегда выполняет байткод.

      Насчет производительности — судить не берусь, но мне ее в целом хватает.
    • 0
      Исследовательские работы по Scala начались еще в 2001 году и были инициированы разработчиком Generic'ов в Java — Мартином Одерски.

      Groovy появился вроде как в 2003г. и разработчик просто не знал о scala, иначе groovy просто не появился бы)

      James Strachan — Scala as the long term replacement for java/javac?
      • +1
        Спасибо, не знал что scala так стар. В википедии правда сказано что оба языка появились в 2003.
        Думаю груви бы появился в любом случае, groovy это логичная надстройка над java, а scala совершенно новый язык в котором иногда даже сложно использовать код на java(разница в collection api)
      • +1
        Слова James Strachan, создателя Groovy:

        «I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.»

        Основной недостаток Groovy — это динамическая типизация, когда тип переменной может быть вычислен только в runtime. В Scala была реализована сложная модель вычисления статических типов на этапе компиляции.

        Один из бонусов type-safe языка, который я люблю — это то, что IDE знает типы и предлагает список полей и методов по Ctrl-Space В Groovy же приходится ползать в документацию.

        Тем не менее для Groovy списывать рано. Для него написано огромное количество библиотек, и использование его для написания скриптов или второстепенных утилит очень оправдано. Однако для основного проекта я бы использовал его с осторожностью.
        • 0
          В нем не динамическая типизация. Тип переменной вычисляется при компиляции в байткод, насколько я понимаю. По край ней мере так это выглядит при декомпиляции.
          • 0
            В нем опциональная / утиная типизация, скажем так. Когда вы пишете def x = «mystring», x.class будет Object. Вывода типов нет.

            C другой стороны, без такой системы типов / поддержки метаклассов вы бы наверное не смогли добавлять или изменять метода / поля в отдельных объектах динамически (через ExpandoMetaClass и иже с ним).
            • 0
              По крайней мере groovy console с вами не согласен:
              groovy> def x = "mystring"
              groovy> x.class
              
              Result: class java.lang.String
              • 0
                Потому что класс обределяется в рантайме. Если посмотреть код через jad, то там будет что-то типа Object x = (Object)«mystring». Если в джаве написать такое, то x.getClass() тоже вернет String.
                • 0
                  понял, спасибо
        • 0
          Кстати, в идее прекрасно работает автокомплит в большей части случаев (моих?).
    • 0
      >Но дается с очень большой ценой — производительность груви в среднем раз в 10 меньше чем явы и не важно байт код это или режим скрипта — все дело в мета программирование и количестве оберток которые нужно дернуть прежде чем добраться до реального метода.

      а вы groovy++ пробовали?
      • 0
        нет, но кажется мне что тогда природу многие прелести груви например DSL.
        • 0
          есть mixed mode
          • –1
            ну тогда это звучит так: мы предлагаем вам новую функциональность, одна из фич которой ее можно отключить. И тогда спрашивается зачем было включать.

            Groovy это groovy, и если его и имеет смысл использовать то только в полном объеме.
            • +3
              нет, не так.
              если код можно вывести-типизировать и этим его ускорить — для него включится статическая типизация, если нет — останется динамическая. и эта вся магия включается одной аннотацией.
  • +1
    Grails хорошо, когда есть задумка на «стартапчик» и пока не пропал угар быстренько слабать. А что делать потом (переписывать на что-то другое) — уже смотреть по необходимости.
  • +1
    Автор, спасибо большое. Все кратко, ясно и лаконично!
  • 0
    «Ключевое слово return указывать не обязательно — по умолчанию будет возвращено значение последней упомянутой переменной в фукции.» == ЛПП. Последнее вычисленное выражение возвращается.
    И это тоже: parent*.action == parent.collect {ch -> child?.action} Справа список нулей. Или оба ch или оба child
    • 0
      То есть даже не нули, а эксепшн

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.