![]() |
|
|
|
| | | | | | | | | | |

Groovy är ett dynamiskt språk som har likheter med bland annat Ruby men som från början skapades för att användas just tillsammans med Java. Groovy har tre stora fördelar som vi ska titta närmare på: det är syntaktiskt väldigt likt Java, det är helt naturligt att använda befintliga Javabibliotek och det är dessutom inga problem att anropa Groovy-kod från Java.
Vi kommer att titta på en hyfsat enkel metod som är implementerad och testad i Java, där vi successivt skriver om både implementation och test i Groovy och slutligen tittar på hur tester och implementationer kan användas i vilken kombination som helst.
Vår metod ordnar en lista strängar efter fallande frekvens, och så här ser den ut i Java:
import org.apache.commons.collections.HashBag;
public class JavaOrderer implements Orderer {
public List<String> orderByFreq(List<String> in) {
final Bag bag = new HashBag(in);
List<String> out = new ArrayList<String>(bag.uniqueSet());
Collections.sort(out, new Comparator<String>() {
public int compare(String a, String b) {
int freq = Integer.valueOf(
bag.getCount(b)).compareTo(bag.getCount(a)
);
return freq != 0 ? freq : a.compareTo(b);
}
});
return out;
}
}
public class OrdererTestUsingJava extends TestCase {
public void testOrderByFreq() {
Orderer orderer = new JavaOrderer();
List<String> unordered = Arrays.asList("b", "d", "b", "b", "a", "c", "a");
List<String> ordered = orderer.orderByFreq(unordered);
assertEquals(Arrays.asList("b","a","c","d"), ordered);
}
}
(A) class GroovyOrderer implements Orderer {
(A) List<String> orderByFreq(List<String> (B) inList) {
final Bag bag = new HashBag(inList)
List<String> out = new ArrayList<String>(bag.uniqueSet())
Collections.sort(out, new Comparator<String>() {
public int compare(String a, String b) {
int freq = Integer.valueOf(bag.getCount(b)).compareTo(bag.getCount(a))
return freq != 0 ? freq : a.compareTo(b)
}
})
return out
}
}
Därefter kan vi byta statiska typdeklarationer mot nyckelordet def (C), och använda en mekanism som kallas coercion, en slags blandning mellan castning och typkonvertering (D):
(C) def orderByFreq(inList) {
(C) def bag = new HashBag(inList)
(C) def out = bag.uniqueSet() (D) as List
Collections.sort(out, new Comparator<String>() {
public int compare(String a, String b) {
(C) def freq = Integer.valueOf(bag.getCount(b)).compareTo(bag.getCount(a))
return freq != 0 ? freq : a.compareTo(b)
}
})
return out
}
def orderByFreq(inList) {
def bag = new HashBag(inList)
def out = bag.uniqueSet() as List
Collections.sort(out, (E) { a, b ->
def freq = Integer.valueOf(bag.getCount(b)).compareTo(bag.getCount(a))
return freq != 0 ? freq : a.compareTo(b)
} (F) as Comparator)
return out
}
Collections.sort(out);
kan man skriva
out.sort()
def orderByFreq(inList) {
def bag = new HashBag(inList)
def out = bag.uniqueSet() as List
(H) out.sort { a, b ->
def freq = bag.getCount(b).compareTo(bag.getCount(a))
return freq != 0 ? freq : a.compareTo(b)
} (I)
return out
}
def orderByFreq(inList) {
def bag = new HashBag(inList)
def out = bag.uniqueSet() as List
out.sort { a, b ->
def freq = bag.getCount(b) (K) <=> bag.getCount(a)
freq != 0 ? freq : a (K) <=> b
}
(J)
}
Slutligen ska vi se hur vi kan anropa Groovy-kod från Java. Vi modifierar vårt enhetstest en smula:
public class OrdererTestUsingJava extends TestCase {
private void doTestOrderByFreq(Orderer orderer) {
List<String> unordered = Arrays.asList("b", "d", "b", "b", "a", "c", "a");
List<String> ordered = orderer.orderByFreq(unordered);
assertEquals(Arrays.asList("b","a","c","d"), ordered);
}
public void testJavaImpl() {
doTestOrderByFreq(new JavaOrderer());
}
public void testGroovyImpl() {
doTestOrderByFreq(new GroovyOrderer());
}
}
class OrdererTestUsingGroovy extends GroovyTestCase {
private def doTestOrderByFreq(orderer) {
def unordered = ["b", "d", "b", "b", "a", "c", "a"] (L)
def ordered = orderer.orderByFreq(unordered)
assert (N) ["b","a","c","d"] == (M) ordered
}
void testJavaImpl() {
doTestOrderByFreq(new JavaOrderer())
}
void testGroovyImpl() {
doTestOrderByFreq(new GroovyOrderer())
}
}
Slutligen några ord om prestanda. Jag skrev ett litet mikrobenchmark som ordnade en lista enligt metoden i artikeln med 100 element 10 000 gånger i följd (med uppvärmning), och Java visade sig vara runt sex gånger snabbare, med 150 millisekunder mot Groovys 900. Sådana här resultat ska man förstås alltid ta med en rejäl nypa salt, men man kan ändå notera två intressanta saker. Till att börja med är Groovy i det här fallet ändå så pass snabbt att man kan köra den aktuella rutinen fler än tio tusen gånger på en sekund, så det är redan idag tillräckligt snabbt för en mängd olika typer av uppgifter. Men än viktigare är att man väldigt lätt kan använda Java för att eliminera flaskhalsar i en Groovy-baserad applikation.
Ett litet projekt med koden från artikeln inklusive benchmark finns att ladda ner från Google Code: http://code.google.com/p/pnehm-java-to-groovy
/.
![]() |
Peter Backlund är Javautvecklare på Citerus. Han diskuterar gärna Grails med dig på peter punkt backlund at citerus punkt se. |

![]() |