2009.08_Groovy na pohybel Javie, z miłością do Javy–wprowadzenie do języka_[Jezyki Programowania].pdf

(1233 KB) Pobierz
441671397 UNPDF
Języki programowania
Groovy
na pohybel Javie, z miłością do Javy
–wprowadzenie do języka
Groovy to nowoczesny, dynamiczny język, w pełni integrujący się
z platformą Java, pozwalając na bezpośrednie korzystanie z mnogości
istniejących bibliotek i szkieletów.
Dowiesz się:
• Jak zacząć programowanie w języku Gro-
ovy, jaka jest jego składnia i budowa;
• Jak łączyć programy napisane w Groovim
z Javą i vice versa.
Powinieneś wiedzieć:
• Jak programować w języku Java.
Java script (ale nie JavaScript)
Kiedy powstał język Java, zachwycił on wie-
lu programistów możliwością bardzo szyb-
kiego wytwarzania aplikacji (zwłaszcza sie-
ciowych lub bazodanowych) w porówna-
niu do C++. Narzucona na poziomie kon-
cepcji języka konieczność zachowywania
pewnego porządku w kodzie, czytelność i
łatwość nauki spowodowały, że wybaczo-
no Javie ułomność związaną z jej ówczesną
wydajnością i zaczęto się nią poważnie in-
teresować. Czy jednak kodowanie w Javie
jest naprawdę takie szybkie? Wiele jej me-
chanizmów i cech (np. mocna kontrola ty-
pów) zostało stworzonych po to, by ustrzec
nas przed popełnianiem błędów, zwłaszcza
tych niewygodnych do wykrycia. Dzięki ta-
kiej koncepcji osiągnęliśmy język, którego
kod jesteśmy w stanie łatwo weryfikować
z użyciem narzędzi. Tym samym zarządza-
nie wielkimi projektami, nad którymi pra-
cują tabuny programistów, jest zwyczajnie
możliwe, a przynajmniej – prostsze. Czy
jednak składnia języka powinna brać pod
uwagę ludzką ułomność, narzucać coś, by
człowiek nie popełnił błędu? Czy nie two-
rzymy tym samym ideologii nie myśl – pro-
gramuj ? Oczywiście celowo ubarwiam tę
kwestię, zmierzam jednak tym samym do
mniej kontrowersyjnego stwierdzenia, że
języki dynamiczne, stojące niejako w opo-
zycji do Javy, dają programiście dużo więk-
szą swobodę wyrażania myśli. Uważam, że
dobrze się dzieje, iż tego typu rozwiąza-
nia zyskują coraz bardziej na popularno-
ści. Często języki dynamicznie typizowa-
ne, o skryptowej naturze, pozwalają zako-
dować coś szybciej, wyrazić myśl w bardziej
naturalny sposób, a szablonowe fragmenty
kodu po prostu w locie wygenerować. Ry-
gor utrzymywania jakości kodu pozostaje
w tym wypadku po stronie programistów,
co może być bolączką podczas pracy zespo-
Poziom
trudności
efekcie można, w zależności od konkret-
nego problemu, stosować odpowiednie
techniki lub łączyć ideologie. Z własnego
doświadczenia wiem, że koncepcja ta jest
ze wszech miar słuszna. Groovy jest bar-
dzo ciekawym pomysłem na rozszerzenie
wiedzy o językach dynamicznych i funk-
cyjnych (zakładam, że większość Czytel-
ników tego artykułu ma przede wszyst-
kim doświadczenie obiektowe, z językami
mocno typowanymi). Groovy powstał ja-
ko konglomerat różnych pomysłów, które
na przestrzeni czasów pojawiły się w war-
tościowych językach programowania. Mo-
że przez to połączenie jest czasem nieco
przesadzony , jednak jego poznanie może
znacząco ułatwić podróże w kierunku ję-
zyków odległych Javie. Siłą Grooviego (dla
programistów Javy) jest to, że ucząc się no-
wej koncepcji, wciąż pozostajemy w świe-
cie dobrze nam znanym i używamy tych
samych bibliotek. Nie będzie to zatem na-
uka od zera.
Artykuł dedykowany jest dla osób, któ-
re o Groovim w ogóle nic nie wiedzą al-
bo jedynie coś, gdzieś, kiedyś słyszeli. Je-
śli masz już, drogi Czytelniku, pewne do-
świadczenie z Groovim i interesujesz się
tworzeniem aplikacji internetowych, za-
chęcam do przeczytania artykułu Ma-
riusza Roga pt. Grails, Groovy i ruszto-
wania na temat szkieletu Grails. Arty-
kuł opublikowany jest w niniejszym wy-
daniu SDJ.
cza tych, którzy przesiąkli pew-
nymi nawykami, nauka nowego
języka programowania (lub choćby okaza-
nie mu zainteresowania) jest porównywal-
na do zdrady partnera. Jest to niestety po-
dejście dość radykalne i leniwe, bowiem z
każdego wartościowego języka (a postaram
się udowodnić, że Groovy do takich należy)
można nauczyć się wiele nowego, nawet je-
śli finalnie pozostanie się przy swoim ulu-
bionym rozwiązaniu. Koncepcja ta została
doskonale opisana w artykule Petera Norvi-
ga pt. Poznaj sztukę programowania w dzie-
sięć lat (dostępnym na stronie internetowej
http://norvig.com/21-days.html ). Autor suge-
ruje, by poznać kilka różnych koncepcyjnie
języków (przynajmniej jeden funkcjonal-
ny, jeden obiektowy i równoległy) do tego
stopnia, by zacząć umieć myśleć w tych ję-
zykach (a nie tylko poznać ich składnię, jed-
nak programować z użyciem dotychczaso-
wych nawyków). Rezultatem takiego do-
świadczenia powinno być szersze spojrze-
nie na programowanie jako sztukę tworze-
nia kodu, z pominięciem ograniczeń narzu-
canych przez pojedyncze rozwiązanie. W
26
08/2009
D la wielu programistów, zwłasz-
441671397.044.png 441671397.045.png 441671397.046.png 441671397.047.png 441671397.001.png 441671397.002.png 441671397.003.png 441671397.004.png 441671397.005.png 441671397.006.png
Groovy
łowej. Można by zatem rzec, iż skrypty nie
są dla idiotów. Chaos, jaki można stworzyć
skryptem choćby w średniej wielkości pro-
jekcie, może pozostać nie do ogarnięcia na-
wet dla programistycznego guru. Czy to
jednak powinno bronić nas przed używa-
niem mniej schematycznych (od Javy) ję-
zyków programowania? Jedynie o Lispie i
SQLu mówi się, iż programowanie w tych
językach składa się przede wszystkim z my-
ślenia, a zapisywanie kodu to jedynie trzy-
dzieści procent czasu. Myślenie jednak nie
boli, natomiast patrzenie na kod, który z ła-
twością można by wygenerować lub stwo-
rzyć z użyciem techniki kopiuj-wklej, mo-
że co wrażliwszych programistów doprowa-
dzić do zapalenia spojówek.
Wystarczy już krytyki na temat Javy – ję-
zyk ten ma wiele dobrych cech. Przez la-
ta Java dorobiła się ogromnej ilości bi-
bliotek, szkieletów, narzędzi programi-
stycznych – stabilnych i pisanych na pro-
fesjonalnym poziomie, często przez uzna-
ne instytucje. Stworzył się standard. Java
jest jedną z najczęściej rozważanych alter-
natyw przy tworzeniu wielkich aplikacji
korporacyjnych, integrujących różne śro-
dowiska, trzon dla wielu rozwiązań webo-
wych. Żaden z języków wyższego poziomu
nie otrzymał tak profesjonalnego wsparcia
i pewnie żaden nie wygenerował twórcom
programów takich zysków, jak Java. Przy-
kładowo Python, który jest językiem prze-
estetycznym i wygodnym w pisaniu, bory-
ka się z nadmiarem niejednorodnych i nie-
kompletnych rozwiązań i bibliotek, często
pisanych amatorsko, na kolanie. Nawet je-
śli na dobrym poziomie, to bez niezbędne-
go wsparcia, zapewniającego profesjonalny
rozwój rozwiązań. Kolejny język nadający
się do szybkiego pisania aplikacji i bardzo
naturalnego sposobu wyrażania myśli – Ja-
vaScript – praktycznie nie istnieje poza śro-
dowiskiem przeglądarek. Powstałe rozwią-
zania są wykorzystywane co najwyżej przez
pasjonatów niż twórców poważnych aplika-
cji, a sam język, ze względu na marginal-
ną wiedzę na jego temat pośród większo-
ści programistów, często nie cieszy się do-
brą opinią.
W takiej sytuacji niesamowitym kompro-
misem byłby język, który pozwoliłby na sko-
rzystanie z ogromu rozwiązań powstałych
dla języka Java, jednak z drugiej strony miał-
by naturę bardziej dynamiczną, pozostawia-
jącą programiście dużą dowolność. Taki ję-
zyk doskonale nadawałby się do pisania mi-
kroprogramów lub małych narzędzi, jak i
wielkich aplikacji. Taki język powinien, w
razie konieczności, pozwalać na implemen-
tację części funkcjonalności bezpośrednio w
języku Java lub w aplikacjach Java być wyko-
rzystywanym do implementacji tych frag-
mentów, które łatwiej jest opisać skrypto-
wo. Taki język.... to Groovy. Gdyby nazwa
JavaScript nie została już (zupełnie nieade-
kwatnie) zarezerwowana, Groovy byłby naj-
pewniej określany w ten właśnie sposób.
Choć może to stwierdzenie nieco na wyrost
– Groovy jest w końcu językiem kompilowa-
nym, zachowuje jednak wiele cech języków
skryptowych.
namiczną, jak i silną typizacją. Mimo że jest
językiem kompilowanym, umożliwia znaczą-
ce modyfikowanie prototypów klas oraz dy-
namiczne uruchamianie kodu. Do podsta-
wowych różnic w stosunku do języka Java na-
leżą: domknięcia, możliwość przeładowywa-
nia operatorów, wyrażenia regularne wbudo-
wane w składnię języka, koncepcja właściwo-
ści klas (ang. properties ) oraz możliwość ewa-
luacji wyrażeń.
Trochę faktów
Oficjalny manual Grooviego we wstępie wita
na pokładzie nowego języka, każe zapiąć pasy
i wznieść się na wyżyny programowana. Lot-
nicze skojarzenie ma zapewne źródło w histo-
rii (a może – legendzie) powstania języka. Je-
go twórca – James Strachan – wpadł na pier-
wotną ideę Grooviego, przeglądając na lotni-
sku, w oczekiwaniu na samolot, artykuły na
temat Pythona. Jako zagorzały programista
Javy, nie miał wielkiego doświadczenia z języ-
kami bardziej dynamicznymi i doznał praw-
dziwego olśnienia, widząc, jak wielkimi skró-
tami myślowymi można posługiwać się, pro-
gramując w Pythonie. Zaczął rozwijać kon-
cepcję języka, czerpiąc z istniejących rozwią-
zań, starając się jednak zachować pełną zgod-
ność z Javą. Podstawową ideą było utworzenie
języka, który bez żadnych dodatkowych me-
chanizmów będzie mógł korzystać z ogromu
bibliotek Javy, jak również, który z poziomu
języka Java będzie rozpoznawany jako spójny
fragment programu. Minęło prawie sześć lat
od tego czasu. Język Groovy, dzięki zapałowi
twórcy i jemu podobnych pasjonatów – po-
wstał i znalazł swoją pozycję. Ma coraz więk-
sze grono zwolenników. Z drugiej strony, po
sześciu latach od powstania, wielu programi-
stów Javy nie zna nawet podstawowych kon-
cepcji Grooviego, którego używanie nie musi
być wcale zdradą Javy, a jedynie jej praktycz-
nym uzupełnieniem. Właśnie im dedykowa-
ny jest ten artykuł.
Groovy jako koncepcja języka powstał w
2003 roku, jednak na pierwszą oficjalną i
stabilną implementację (wersja 1.0) trzeba
było czekać aż do 2007 roku. Jeszcze w tym
samym roku została wydana znacznie po-
prawiona wersja 1.1, która dla podkreślenia
zmian została szybko przemianowana na 1.5.
W chwili pisania artykułu dostępna była wer-
sja 1.6.3 z maja 2009 roku. Ostatnie dwa la-
ta to okres silnego zainteresowania językiem
oraz rozwoju dedykowanych szkieletów i na-
rzędzi. Aktualnie trwają prace nad jego stan-
daryzacją zgodnie z Java Community Process
(JSR241).
Język Groovy definiuje się jako dynamicz-
ny (często także pada określenie – skrypto-
wy) język obiektowy dedykowany platfor-
mie Java. Najczęściej porównuje się go do ta-
kich języków jak Python, Ruby, Perl i Small-
talk. Groovy charakteryzuje się zarówno dy-
Web is dead
Web is dead , czyli nieco bardziej cyberpun-
kowy Hello world . W końcu i tak chodzi tyl-
ko o wygenerowanie jakiegokolwiek tekstu na
ekranie. A ponieważ jest to offline'owy ekran
konsoli systemowej, tekst będzie na miejscu.
Niniejszym ogłaszam najkrótszy w historii
SDJ rozdział poświęcony temu zagadnieniu.
Oto rozwiązanie
groovy -e "print 'Web is dead'"
Ktoś chciał coś powiedzieć o statycznej me-
todzie main jakiejś tam klasy, przyjmującej w
parametrze tablicę? Hmm...
Środowisko języka Groovy
Przedstawiony powyżej pierwszy program
niewiele nam jeszcze mówi o samym języ-
ku i możliwości uruchamiania jego progra-
mów. Zajmijmy się najpierw tym drugiem.
Groovy pozwala kompilować kod do plików
. class , pozostając nieodróżnialnym od Ja-
vy dla maszyny wirtualnej tego języka. Mo-
że też, tak jak zrobiliśmy to w przypadku
pierwszej aplikacji, uruchomić kod bezpo-
średnio z wiersza poleceń – dzięki przełącz-
nikowi -e polecenia groovy . Kolejną, bardzo
wygodną w trakcie nauki opcją jest konsola
(uruchamiana poleceniem groovyConsole ),
w której szybko możemy pisać małe frag-
menty kodu i obserwować ich działanie.
Rysunek 1. Konsola języka Groovy pozwala
w łatwy sposób testować małe programy, bez
konieczności jawnej kompilacji
www.sdjournal.org
27
441671397.007.png 441671397.008.png 441671397.009.png 441671397.010.png 441671397.011.png 441671397.012.png 441671397.013.png 441671397.014.png 441671397.015.png 441671397.016.png 441671397.017.png 441671397.018.png
Języki programowania
Wygląd konsoli języka zaprezentowano na
Rysunku 1.
Pracując z konsolą, bądź uruchamiając
programy z użyciem narzędzia groovy , mo-
żemy odnieść wrażenie, że Groovy jest języ-
kiem interpretowanym. Gdyby tak było, je-
go integracja z Javą nie byłaby już taka pro-
sta. W rzeczywistości Groovy zawsze tworzy
pliki class , choć czasem może to być ukryte
dla programisty – kompilator może umiesz-
czać klasy w plikach tymczasowych lub bez-
pośrednio w pamięci. Zazwyczaj jednak bę-
dziemy jawnie odwoływać się do standar-
dowych plików . class . By je otrzymać – po-
trzebujemy kompilatora, a więc narzędzia
groovyc . Polecenie
kie niezbędne pliki są osadzone w jednym
pliku jar , zajmującym ponad 4MB. Uru-
chomienie skompilowanej klasy Groovy
( Test.class ) będzie zatem wyglądało nastę-
pująco:
nej typizacji obiektów. Silna typizacja, będą-
ca cechą języka Java, niejednokrotnie wymu-
sza konieczność częstego jawnego rzutowa-
nia. Groovy rozwiązuje ten problem w sytu-
acjach, w których nie jest to potrzebne, w in-
nych pozwala natomiast na zachowanie kon-
troli typów. Oto przykład:
java -cp groovy-all-1.6.0.jar; Test
Podstawowa składnia
Wiemy już, jak uruchamiać programy języka
Groovy, skupmy się zatem na prostych przy-
kładach mających na celu zobrazowanie cech
języka. Zachęcam do uruchamiania ich z po-
ziomu konsoli groovyConsole . Zakładam, że
Czytelnicy tego artykułu znają przynajmniej
na podstawowym poziomie Javę, postaram
się więc położyć szczególny nacisk na wskaza-
nie różnic między tym językiem a Groovym.
Przedstawiony wcześniej pierwszy, jed-
nowersowy przykład ( Web is dead ) wska-
zał już na kilka istotnych różnic (i skró-
tów) przyjętych przez język Groovy. Funk-
cja print została użyta bez nawiasów, za-
brakło też końcowego średnika. Oba te ele-
menty nie są wymagane, o ile jasno z kon-
tekstu można zrozumieć intencje wyko-
nania kodu. Średnik zwykle przyda się
w przypadku umieszczenia w jednej linii
programu kilku niezależnych wywołań.
Pomijanie nawiasów w wykonaniu funk-
cji zwykle może zagmatwać czytelność,
choć zwyczajowo opuszcza się je dla funk-
cji print . Ponadto będzie to bardzo przy-
datne przy pracy z domknięciami, o czym
w dalszej części artykułu.
Podstawową różnicą między Javą a Gro-
ovim jest możliwość używania dynamicz-
def a=1
Integer b = 1
a = "test"
b = "test" //błąd
W języku Groovy nie musimy tworzyć kla-
sy, by napisać prosty kod (kompilator utwo-
rzy ją w takiej sytuacji domyślnie). Możemy
zatem bezpośrednio zająć się pisaniem kodu
lub zamiast klas korzystać wyłącznie z funk-
cji. Deklaruje się je następująco:
groovyc *.groovy
utworzy pliki .class dla zadanego katalogu.
Od tego momentu będziemy mogli skorzy-
stać z nich w jakimś projekcie języka Java
lub zwyczajnie uruchomić. Ciekawą opcją
kompilatora groovyc jest możliwość użycia
narzędzia javac celem jednoczesnego skom-
pilowania plików .groovy i .java i rozwiąza-
nia zależności tkwiących między tymi plika-
mi. Służy do tego przełącznik -j :
def poleKola(promien) {
Math.PI * promien**2
}
Powyższy kod ma kilka ciekawych cech. Po
pierwsze – nie określamy typu zwracane-
go, wiemy już zatem, że będzie on miał dy-
namiczny charakter. Po drugie – odwołu-
jemy się tu do właściwości PI klasy Math
tej samej, której używa język Java. Po trze-
cie – użyliśmy nieobecnego w Javie opera-
tora potęgowania ( ** ). Finalnie zaś – zwra-
camy wartość funkcji bez użycia słowa klu-
czowego return . Użycie go jest opcjonal-
ne – w przypadku jego pominięcia zostanie
wzięta pod uwagę wartość ostatniej linii ko-
du funkcji.
groovyc -j Test.groovy Main.java
Skompilowane pliki .groovy będziemy
uruchamiać tak jak każdy program Ja-
vy. Musimy tylko pamiętać o dodaniu do
ścieżki niezbędnych bibliotek. Ponieważ
ich ilość jest niemała, możemy skorzy-
stać z dystrybucji języka, w której wszyst-
Niestandardowe operatory
Poniżej znajduje się opis operatorów języka Groovy, które nie mają swoich bezpośrednich odpowiedników w Javie lub które w Javie występu-
ją, lecz zyskały tutaj dodatkowe znaczenie.
a ** b – potęgowanie; podnosi a do potęgi b .
*lista – konwertuje listę do ciągu oddzielnych parametrów; w praktyce pozwala na przekazanie funkcjom parametrów w posta-
ci listy, np. "text".substring(*[1,2]) ; operator może też być użyteczny przy dodawaniu nowych elementów do listy lub mapy, np.:
[1,2,3,*[4,5,6]] utworzy sześcioelementową, płaską listę.
a[b] – udostępnia obiekt pod wskazanym indeksem, działa zarówno z tablicami, jak również listami i mapami; umożliwia odczyt i zapis da-
nych.
a << b – klasyczne przesunięcie bitowe w lewo, jednak dla niektórych typów posiada przeładowane znaczenie typu dodaj , uzupełnij o ele-
ment. W tej formie operuje na obiektach StringBuffer , klasach typu Writer , plikach, gniazdach, listach i metaobiektach.
<=> – komparator, ze względu na wygląd nazywany statkiem kosmicznym (ang spaceship ); służy do porównywania wartości obiektów.
a as typ – tworzy wymuszenie rzutowania bądź alias dla jakiegoś typu. W tym pierwszym przypadku możemy użyć operatora np. do za-
inicjalizowania obiektu z użyciem listy: def obj = [1,2,3] as MyClass . Aliasowanie pozwala natomiast na uniknięcie konliktów nazw,
poprzez ich import pod nową nazwą, np. import java.sql.Date as SQLDate
a .@ b – bezpośredni dostęp (z pominięciem metody get ) do składnika b obiektu a .
a .& b – zwraca referencję do metody b obiektu a w postaci domknięcia; kontekst obiektu zostaje zachowany (odwołania z użyciem this );
operator może mieć zastosowanie np. przy przekazywaniu metody w postaci parametru do funkcji oczekujących na wejściu domknięcia
(np. lista.each(obiekt.&metoda) )
a .. b – operator zakresu, np (1..20) ; istnieje możliwość stworzenia przedziału prawostronnie otwartego, np. (100..<105) .
a *. b – odnosi się do właściwości lub metody b każdego obiektu zawartego w kolekcji a ; przykładowo kod ["a","b","c"]*.toUpperCase
() zwróci w rezultacie listę ["A","B","C"] .
a ?. b – opcjonalny dostęp do elementu; b zostanie użyte, tylko jeśli a nie ma wartości null ; pozwala uniknąć pisania dodatkowych wa-
runków i znacząco zmniejsza ryzyko wystąpienia w kodzie wyjątków typu Null pointer exception .
==~ – operator dopasowania w wyrażeniach regularnych.
=~ – operator przeszukiwania w wyrażeniach regularnych.
28
08/2009
441671397.019.png 441671397.020.png 441671397.021.png 441671397.022.png 441671397.023.png 441671397.024.png 441671397.025.png
 
Groovy
GString
Operacje na łańcuchach znaków są często
niezwykle istotnym elementem programów,
a przy niewygodnych mechanizmach potra-
fią znacząco utrudnić programistom życie.
Groovy wychodzi tu na pomoc z rozbudo-
waną koncepcją obsługi tekstów i wbudo-
wanym w język wsparciem dla wyrażeń re-
gularnych. Oprócz implementacji klasycz-
nych obiektów java.lang.String , znaj-
dziemy tu rozszerzenie w postaci klasy
groovy.lang.GString , która umożliwia do-
stęp do zmiennych z poziomu łańcuchów
znaków, jak ma to miejsce w wielu językach
skryptowych:
dykowanych operatorów, celem odróżnienia
od zwykłych łańcuchów znaków:
Pierwszą dostrzegalną różnicą jest uży-
cie dynamicznego typu ( def ). Dzięki te-
mu polu author będziemy mogli, w za-
leżności od potrzeby, przypisać np. prosty
napis, obiekt klasy Person lub listę tych
obiektów.
Nigdzie w przykładzie nie umieściliśmy
operatora zakresu – w przypadku Groovie-
go nie oznacza to jednak, że składowe klasy
przyjmą domyślnie zakres pakietu. Dla me-
tod domyślnym zakresem jest public , nato-
miast dla pól – private .
Ponieważ jak dotąd nie zdefiniowaliśmy w
klasie żadnego konstruktora, mamy, podob-
nie jak w Javie, do dyspozycji bezparametro-
wy konstruktor domyślny. Ponadto standar-
dowo Groovy udostępnia jeszcze jeden kon-
struktor, dzięki któremu możemy w trakcie
inicjalizacji obiektu ustawić wartości pól za
pomocą mapy:
def pattern = ~/a(.*)d/
Możemy teraz spróbować porównać dowol-
ny napis ze zdefiniowanym wzorcem – słu-
ży do tego operator ==~ :
if( 'abc' ==~ pattern ) { … }
Chcąc otrzymać wszystkie odpowiadające
wzorcowi dopasowania, należy skorzystać
z kolejnego operatora, który w rezultacie
zwróci listę wyników:
public class Person {
def irstname, lastname
String toString() {
"$irstname $lastname"
}}
def matches = 'abcd' =~ pattern
Dla naszego przykładu będzie to dwuele-
mentowa lista ['abcd', 'bc']
Jak widzimy na tym prostym przykładzie,
łatwo możemy pozbyć się niewygodnej kon-
katenacji łańcuchów. Może mieć to zastoso-
wanie w wielu sytuacjach, np. w servletach,
przy tworzeniu zapytań SQL itp.
Rozróżnienie między klasycznym Stringiem
a GStringiem odbywa się po użytych znakach
cytowania. Pojedynczy cudzysłów tworzy
obiekty klasy java.lang.String i w tej sy-
tuacji nie ma możliwości interpolacji zmien-
nych. Podwójne cudzysłowy umożliwiają sko-
rzystanie z zalet obiektów GString .
Groovy wprowadza jeszcze jedno bardzo
ciekawe udogodnienie, umożliwiające ope-
rowanie na długich, wielowersowych łańcu-
chach znaków. Służą do tego pojedyncze lub
podwójne cudzysłowie (w zależności, czy
chcemy rozwijać wartości wyrażeń, czy nie),
użyte trzykrotnie:
Tworzenie klas – podstawy
Definiowanie klas w języku Groovy w wersji
podstawowej przypomina mocno Javę. Na wyż-
szym poziomie szczegółowości pojawia się tu
jednak wiele elementów rozbudowujących ba-
zową składnię. W niniejszym opisie stworzymy,
krok po kroku, przykładową klasę, skupiając się
na istotnych cechach języka. Niech będzie to
klasa opisująca języki programowania. Zacznij-
my od kilku podstawowych pól:
def pl = new ProgrammingLanguage(name:
"Perl", author: "Larry Wall")
Konstruktory te będą dostępne dopóty nie
zdefiniujemy własnych. Implementacja kon-
struktora wygląda tak samo jak w Javie:
ProgrammingLanguage(String name) {
this.name = name
}
public class ProgrammingLanguage {
String name
def author
String helloWorldCode
}
Gdybyśmy konstruowali naszą przykłado-
wą klasę w Javie, z pewnością uzupełni-
libyśmy ją o metody get i set dla poszcze-
gólnych pól, zwłaszcza że są one prywat-
ne i nie powinniśmy mieć do nich bezpo-
Listing 1. Przykład użycia budowniczego SwingBuilder do szybkiego tworzenia interfejsu użytkownika
import groovy.swing.SwingBuilder
def txt = """Dzisiaj jest ${new Date()}.
Test długiego napisu w języku Groovy"""
swing = new SwingBuilder ()
frame = swing . frame ( title: ' Groovy Builder ') {
menuBar {
menu (' Help ') {
menuItem ' Help '
menuItem ' About '
}
}
panel {
boxLayout ( axis: javax . swing . BoxLayout . Y_AXIS )
label ' Hello World '
button (
text: ' Exit ',
actionPerformed: { event -> System . exit ( 0 )}
)
}
}
Kolejnym rozszerzeniem jest możliwość
używania operatorów << i <<= do konkate-
nacji stringów. Jest to dość czytelne odróż-
nienie operacji łączenia napisów od doda-
wania numerycznego (choć operatory + i
+= również funkcjonują prawidłowo na tek-
stach). Najbardziej przydatna jest tu możli-
wość użycia operatora << na obiektach kla-
sy StingBuffer zamiast metody append .
Pisząc o operacjach na tekstach, nie sposób
nie wspomnieć o wyrażeniach regularnych,
które w Groovim mają pełne wsparcie bez-
pośrednio z poziomu języka. Przyjrzyjmy się
zupełnym podstawom, skupiając się przede
wszystkim na składni (wyrażenie regularne
to osobny temat, wykraczający daleko poza
zakres tego artykułu). Definicja wzorca wy-
rażenia regularnego odbywa się z użyciem de-
frame . pack ()
frame . show ()
www.sdjournal.org
29
441671397.026.png 441671397.027.png 441671397.028.png 441671397.029.png 441671397.030.png 441671397.031.png 441671397.032.png 441671397.033.png 441671397.034.png 441671397.035.png 441671397.036.png
Języki programowania
średniego dostępu. Zróbmy eksperyment
w Groovim:
należy to zrobić jawnie, tak jak pokazano to
na przykładzie dla właściwości author .
Gdybyśmy w ogóle nie chcieli mieć metod
dla jakiegoś pola, wystarczy zadeklarować je
jako private . Groovy generuje metody tylko
dla właściwości o niezdefiniowanym zakre-
sie. Nic też nie stoi na przeszkodzie, by nadpi-
sać metodę pobierającą wartość lub ją zwraca-
jącą. Będziemy musieli to zrobić dla sytuacji,
w których metoda będzie miała za zadanie
wykonać dodatkowe czynności lub kiedy bę-
dziemy chcieli ograniczyć jej widoczność (np.
do protected ). Jeśli właściwość klasy zosta-
nie zadeklarowana jako final , zostanie natu-
ralnie utworzona jedynie metoda get .
Wiemy już, jak definiować klasy, ich po-
la, metody i specjalne pola – właściwości.
Podobnie jak w przypadku języka Java, kla-
sy mogą dziedziczyć po sobie z użyciem kon-
strukcji extends NazwaNadklasy . Natomiast
mamy tu ograniczenia w postaci braku moż-
liwości używania klas wewnętrznych (mo-
żemy zamiast nich skorzystać z domknięć).
Również interfejsy wymagają specjalnego
traktowania. Zostało to opisane w dalszej czę-
ści artykułu.
dynamicznej typizacji, zatem obiekty umiesz-
czane na liście mogą być dowolnego typu.
W sposób zbliżony do list tworzyć bę-
dziemy mapy (a konkretnie obiekty klasy
LinkedHashMap ):
def sch = new ProgrammingLanguage("Scheme")
sch.author = ["Guy L. Steele", "Gerald Jay
Sussman"]
Zadziwiająco – powyższy kod skompiluje
się. Co więcej, również taki kod nie zwróci
żadnego błędu:
def colors = [ white: "#FFFFFF", red:
"#FF0000" ];
Korzystając z powyżej notacji, łatwo możemy
utworzyć pustą listę ( [] ) oraz pustą mapę ( [:] ).
Definicja tablicy (jest to raczej rzadko uży-
wana w Groovim struktura danych) wymaga
określenia konkretnego typu tablicowego (ce-
lem odróżnienia od listy), np.
sch.setHelloWorldCode('(display "Hello
World!")')
Myślę, że osoby znające np. podstawy języ-
ka C# mogą już wiedzieć, co się stało. Gro-
ovy chroni nas przed koniecznością pisania
oczywistego kodu, którego apogeum stano-
wią wszechobecne metody get i set . Zaledwie
w znikomej ilości przypadków metody te ro-
bią cokolwiek ponad ustawianie wartości
pól prywatnych. Łatwo można je zatem ge-
nerować, co jest cechą wielu środowisk pro-
gramistycznych języka Java. W przypadku
Grooviego – zrobi to za nas sam język! Upo-
rządkujmy wiedzę – deklarując pole klasy
bez podania zakresu widoczności, tworzy-
my de facto właściwość (ang. property ), któ-
ra jest prywatna, automatycznie jednak zo-
staną dla niej wygenerowane publiczne me-
tody get i set . Możemy odwoływać się do nich
przez nazwę, jednak również bezpośrednie
odwołanie do pola klasy uruchomi w rzeczy-
wistości metodę. Jedynie w obrębie samej
klasy będziemy korzystać bezpośrednio ze
zmiennych, a nie metod. Stwórzmy na przy-
kład metodę toString :
int[] numbers = [1,2,3]
Zwróćmy uwagę, że elementy tablicy są za-
inicjalizowane tak jak lista – z użyciem kwa-
dratowych nawiasów. W Javie użylibyśmy tu
nawiasów klamrowych.
Specyficznym typem, który nie posiada
swojego bezpośredniego odpowiednika w Ja-
vie, jest zakres (ang. range ) definiujący ciąg
kolejnych elementów:
Tablice, listy, mapy i zakresy
W Groovim znacznie częściej niż w Javie bę-
dziemy operować na tablicach i mapach dzię-
ki możliwości ich szybkiego, dynamicznego
tworzenia. Tego typu konstrukcje są zresztą
domeną wielu języków dynamicznych – w
Lispie praktycznie wszystko jest listą, w Ja-
vaScripcie każdy obiekt będzie mapą (tabli-
cą asocjacyjną) itp.
Groovy umożliwia tworzenie kolekcji w
sposób identyczny jak w Javie, jednak częściej
korzystać będziemy ze znacznie szybszej no-
tacji operatorowej:
def zakr = 100..200
Zakresy mogą mieć wiele praktycznych za-
stosowań, jak np. iterowanie pętli po kolej-
nych elementach:
for( i in 1..10 ) { ... }
lub wypełnianie list kolejnymi wartościami
(przykład tworzy listę elementów od 1 do 5
oraz od 20 do 25, czyli łączy ze sobą dwa za-
kresy):
String toString() {
"$name, created by ${getAuthor()}"
}
list = [*(1..5), *(20..25)]
def lista = [1,2,3,"tekst", new Object()]
Ponieważ jest to metoda tej samej klasy, nie
mamy potrzeby korzystania z metody get . W
razie konieczności możemy jej użyć, jednak
Zapis powyżej tworzy kolekcję typu ArrayList
i wypełnia ją pięcioma obiektami. Używamy tu
Operatory i ich przeładowywanie
Język Groovy wprowadza kilka ciekawych
operatorów. Część z nich opiszemy bar-
Iterowanie z Groovim
Groovy rozszerza klasę java.lang.Object o dodatkowe metody ułatwiające iterowanie po elementach z użyciem domknięć, co praktycznie
zwalnia programistę z konieczności używania pętli. Metody te można stosować dla wszelkiego rodzaju kolekcji, enumeracji, zakresów i łańcu-
chów znaków. Poniżej przedstawiono ich listę wraz z przykładami użycia. Każda z opisanych tu metod przyjmuje w parametrze domknięcie.
any – zwraca wartość true , jeśli domknięcie zwróci taką wartość dla przynajmniej jednego z elementów. Przykładowo, kod [null, null,
1, null].any{ it != null } sprawdzi, czy lista zawiera niepuste elementy.
collect – zwraca listę wartość zwróconych przez domknięcie dla każdego z elementów wejściowych. Przykładowo, "text".collect{
it.charAt(0) } zwróci listę znaków składających się na napis wejściowy.
each – uruchamia przekazane domknięcie dla każdego elementu listy wejściowej. W rezultacie zwraca listę wejściową.
eachWithIndex – podobnie jak each , ale domknięcie przyjmuje jeszcze drugi parametr, będący indeksem obiektu w kolekcji.
every – działa podobnie jak any , jednak zwraca wartość true ,tylko jeśli dla wszystkich elementów wejściowych domknięcie zwróciło war-
tość true .
ind – przekaże w rezultacie pierwszy element z listy, dla którego domknięcie zwróci wartość true .
indAll – jak wyżej, ale wygeneruje listę wszystkich wartości zgodnych z domknięciem wejściowym. Przykładowo, kod (1..50).indAll{
it % 2 == 0 } zwróci listę liczb parzystych w zadanym zakresie.
indIndexOf – podobnie jak ind , ale zwraca indeks zgodnego elementu.
30
08/2009
441671397.037.png 441671397.038.png 441671397.039.png 441671397.040.png 441671397.041.png 441671397.042.png 441671397.043.png
 
Zgłoś jeśli naruszono regulamin