Groovy is a scripting language that compiles to the Java Virtual Machine. It would be more-aptly named JavaScript if that name were not already taken, but it has many similarities to Python. In fact, some of the libraries implemented for Groovy, such as TableSaw, attempt to take it in the same Data Science direction as Python.
This post will provide an introduction to the Groovy language using Jupyter notebook with BeakerX, and provides specific applications to Data Science. It begins with a tour of the Groovy language, then describes some of the most interesting features that the language provides. We give a comparison to Java with some notes for making integration with Java environments easier. We finish-off with applications and examples in Data Science.
This notebook takes code and examples from this github repo: https://github.com/twosigma/beakerx
Getting Started
You can get started with Groovy in a few different ways. After installing Groovy, the console (comes with Groovy distribution) is a Java Swing application where we can write and run code, interactively.
\\( groovyconsole
Or you can run a script, directly.
\\) groovy your-script.groovy
In this post we will use Jupyter with the BeakerX JVM kernel. BeakerX provides a variety of languages and support transforming data structures among them. This makes it ideal for learning and prototyping. You can get started with BeakerX using Docker.
$ docker run -p 8888:8888 beakerx/beakerx
Introduction
Basic syntax
We provide the obligatory hello world example using a simple println statement to print output to the console.
class Example {
static void main(String[] args) {
println('Hello World');
}
}
Example.main()
Hello World
null
By default, Groovy includes the following libraries in your code, so you don’t need to explicitly import them.
import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal
null
Groovy supports all Java types (primitive and reference types).
All primitive types are auto-converted to their wrapper types. So int a = 2
will become Integer a = 2
When declaring variables we can do one of the followings:
- Do not use any type (that will create a global variable):
a = 2
- Use keyword def (that will create a local variable):
def a = 2
- Use the actual type (that will create a local variable of strict type Integer):
int a = 3
When no type is used, variables act like they are of type Object, so they can be reassigned to different types.
a = 2
printf "%s - %s%n", a.getClass().getName(), a
a = "apple"
printf "%s - %s%n", a.getClass().getName(), a
java.lang.Integer - 2
java.lang.String - apple
null
Running the code
The code outside methods but still in a script is copied to at run to an object method. So during runtime everything is inside methods. In that sense, this feature allows the variables declared in a method to be accessible to other methods.
Groovy keeps these global variables in a map like object (groovy.lang.Binding
).
When def is used, variables act like they are of type Object, so they can be reassigned to different types (same as when no type is used):
//';' should be used after each statement, but is not necessary in beakerx cells
//def is a keyword used in Groovy to define an identifier
def c = 1; //local variable
d = 2; //global variable - var with no type are global so they can be accessed across methods
2
c //error - var declared with def are local, so they cannot be accessed across methods
groovy.lang.MissingPropertyException: No such property: c for class: script1561051888331
at this cell line 1
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.runScript(GroovyCodeRunner.java:94)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:59)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:32)
d //this works
2
Data types
Using actual types (same as Java types). They follow strict typing rules (just like Java). So they cannot be reassigned to different types:
int a = 2
println a
a = "apple"
println a
2
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'apple' with class 'java.lang.String' to class 'int'
at this cell line 3
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.runScript(GroovyCodeRunner.java:94)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:59)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:32)
Like def
variables they are also local, so they cannot be accessed across methods.
int e = 2
void printVars() {
println e;
}
printVars();
groovy.lang.MissingPropertyException: No such property: e for class: script1561051968611
at script1561051968611.printVars(script1561051968611:4)
at this cell line 7
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.runScript(GroovyCodeRunner.java:94)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:59)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:32)
//remove variables
binding.variables.remove 'a'
binding.variables.remove 'b'
binding.variables.remove 'c'
binding.variables.remove 'd'
binding.variables.remove 'e'
null
As seen above, Groovy uses Objects for everything (int is printed as java.lang.Integer). Primitives are auto-converted to their wrapper type.
int a = 2
printf("%s - %s%n", a.getClass(), a.getClass().isPrimitive())
def b = 2
printf "%s - %s%n", b.getClass(), b.getClass().isPrimitive()
c = 2
printf "%s - %s%n", c.getClass(), c.getClass().isPrimitive()
double d = 2.2
printf "%s - %s%n", d.getClass(), d.getClass().isPrimitive()
e = 2.3//no type
printf "%s - %s%n", e.getClass(), e.getClass().isPrimitive()
class java.lang.Integer - false
class java.lang.Integer - false
class java.lang.Integer - false
class java.lang.Double - false
class java.math.BigDecimal - false
null
All of the variables are initialized (even local) with their default values (just like instance variable).
def a //initialized with null
println a
String s //initialized with null
println s
int b//initialized with 0
println b
println b + 3
boolean bool//initialized with false
println bool
null
null
0
3
false
null
Using actual types.
int sum(int x, int y) {
x + y;
}
println sum(1, 3)
4
null
Using def
.
def sum(def x, def y) {
x + y;
}
println sum(1, 3)
4
null
Using no types with parameters.
def sum(x, y) {
x + y;
}
println sum(1, 3)
4
null
Methods must return def or actual type.
sum(x, y) {
x + y;
}
println sum(1, 3)
groovy.lang.MissingPropertyException: No such property: x for class: script1561052241554
at this cell line 1
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.runScript(GroovyCodeRunner.java:94)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:59)
at com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:32)
class Example {
static void main(String[] args) {
//Example of a int datatype
int x = 5;
//Example of a long datatype
long y = 100L;
//Example of a floating point datatype
float a = 10.56f;
//Example of a double datatype
double b = 10.5e40;
//Example of a BigInteger datatype
BigInteger bi = 30g;
//Example of a BigDecimal datatype
BigDecimal bd = 3.5g;
println(x);
println(y);
println(a);
println(b);
println(bi);
println(bd);
}
}
Example.main()
5
100
10.56
1.05E41
30
3.5
null
Features
Groovy has many different features. We have seen a few of these, earlier, but the others are mentioned, here.
- Support for both static and dynamic typing
- Support for operator overloading
- Native syntax for lists and associative arrays
- Native support for regular expressions
- Native support for various markup languages such as XML and HTML.
- Similar syntax to Java
- Use of existing Java libraries
- Extends the java.lang.Object
Support for regular expressions
def m = "Groovy is groovy" =~ /(G|g)roovy/
println m[0][0] // The first whole match (i.e. the first word Groovy)
println m[0][1] // The first group in the first match (i.e. G)
println m[1][0] // The second whole match (i.e. the word groovy)
println m[1][1] // The first group in the second match (i.e. g)
Groovy
G
groovy
g
null
Support for markup languages
One of the most used classes for creating HTML or XML markup.
import groovy.xml.MarkupBuilder
def xml = new MarkupBuilder()
groovy.xml.MarkupBuilder@7500ce0e
Liberal use of closures
//closure example
timesTwo = {x -> x*2}
script1556559307332$_run_closure1@cad3663
timesTwo(4)
8
timesTwo("Multiplying Strings!")
Multiplying Strings!Multiplying Strings!
sin(3.1415)
9.265358966049026E-5
Comparison of Groovy with Java
Basic differences
- automatically a wrapping a class called Script for every program
- default access specifier is public
- getters and setters are automatically generated for class members
- abbreviated commands, such as
println
- semicolons
;
and paraentheses()
are optional - dynamic typing with the
def <var>
keyword (locar var), or with no prefix<var>
(global var) - string interpolation (GString) is performed with
\\(
operator, such as"Hello, \\){firstName[0]}. $name"
- “““multi-line strings are also allowed”””
- implicit truthy
if(100)
because 100 exists
New operators
-
conditional operators
- safe navigation
?
operator checks for properties, such asif(company.getContact()?.getAddress()?.getCountry() == Country.NEW_ZEALAND) { ... }
means If the contact or the address are null, the result of the left side will just be null, but no exception will be thrown. - ternary / elvis
?
operatordef name = client.getName() ?: ""
will assign client.getName() if it isn’t false and the empty string, otherwise
- safe navigation
-
type operators
- spaceship
<=>
delegates to the compareTo() method:def x = 1 <=> 2; println x; // calls Integer.compareTo
- identity
is()
tests object reference equality, while==
checks equality with.equals()
- coercion
as
converts an object from one type to another (using.asType()
), without assignment compatibility, which is different from casting:String s = "1.1"; BigDecimal bd = s as BigDecimal; println bd.class.name
- spaceship
Using methods
- a function used in a script will be compiled to a method within an object
return
keyword is optional- method operators
- method pointer
.&
stores a reference to a method in a variable:def power = Math.&pow; def result = power(2, 4);
- call operator
()
an object with a call method can be called directly:class A{def call(println("hi"){}}; def a = new A(); a();
- method pointer
- closures
- like Java8 lambdas
- anonymous first-class functions are often called lambda functions
def power = { int x, int y -> return Math.pow(x, y) }; println power(2, 3)
- currying
- memoization
Collections: list and map
- list and map operators
- subscript
[]
allows to read/write to collections and maps:def list = [2, 4]; println list[0]; def map = [x: 2, y: 4]; println map['x']
- membership
in
test whether value is in the target collection:def numbers = [2,4,6,8]; println 2 in numbers
- spread-dot
*.
invokes an action on all items of an aggregate object:def lists = [[1], [10, 20, 30], [6, 8]]; def sizes = lists*.size(); //[1, 3, 2]
range..
to create ranges of objects:def numbers = 1..5; println numbers
- subscript
- create an ArrayList with the given numbers:
def list = [1,1,2,3,5]
- closures make it easy to iterate, filter and transform lists
- iterate a list using a passed closure executed once for each element, implicitly passed, as a parameter to the closure:
list.each { println it }
- filter a list:
list.findAll { it % 2 == 0 }
- transform a list:
list.collect { it * it }
- improve:
["Hello", "World"].collect { it.toUpperCase() }
using the spread-dot:["Hello", "World"]*.toUpperCase()
- Collection (and Iterable) interfaces provide some more methods, like
any
orevery
- iterate a list using a passed closure executed once for each element, implicitly passed, as a parameter to the closure:
- maps act similar to lists
def key = 'Key3' def aMap = [ 'Key1': 'Value 1', // Put key1 -> Value 1 to the map Key2: 'Value 2', // You can also skip the quotes, the key will automatically be a String (key): 'Another value' // If you want the key to be the value of a variable, you need to put it in parantheses ]
Applications in Data Science
Dataframes with Tablesaw
Tablesaw is easy to add to the BeakerX Groovy kernel. Tablesaw provides the ability to easily transform, summarize, and filter data, as well as computing descriptive statistics and fundamental machine learning algorithms.
Two helpful demo notebooks (scala) include:
Add using mvn
.
%%classpath add mvn
tech.tablesaw tablesaw-plot 0.11.4
tech.tablesaw tablesaw-smile 0.11.4
tech.tablesaw tablesaw-beakerx 0.11.4
%import tech.tablesaw.aggregate.*
%import tech.tablesaw.api.*
%import tech.tablesaw.api.ml.clustering.*
%import tech.tablesaw.api.ml.regression.*
%import tech.tablesaw.columns.*
// display Tablesaw tables with BeakerX table display widget
tech.tablesaw.beakerx.TablesawDisplayer.register()
null
Read .csv data.
tornadoes = Table.read().csv("../doc/resources/data/tornadoes_2014.csv")
Print the dataset structure.
tornadoes.structure()
Get header names.
tornadoes.columnNames()
[Date, Time, State, State No, Scale, Injuries, Fatalities, Start Lat, Start Lon, Length, Width]
Displays the row and column counts.
tornadoes.shape()
908 rows X 11 cols
Displays the first n rows.
tornadoes.first(3)
import static tech.tablesaw.api.QueryHelper.column
tornadoes.structure().selectWhere(column("Column Type").isEqualTo("FLOAT"))
Summarize the data in each column.
tornadoes.summary()
Table summary for: tornadoes_2014.csv
Column: Date
Measure | Value |
---------------------------
Count | 908 |
Missing | 0 |
Earliest | 2014-01-11 |
Latest | 2014-12-29 |
Column: Time
Measure | Value |
----------------------
Count | 908 |
Missing | 0 |
Earliest | 00:01 |
Latest | 23:59 |
Column: State
Category | Count |
----------------------
GA | 32 |
NM | 15 |
MT | 8 |
CO | 49 |
WV | 9 |
IN | 28 |
MD | 2 |
CA | 9 |
AL | 55 |
TN | 18 |
... | ... |
MO | 47 |
ME | 4 |
LA | 15 |
MI | 13 |
SC | 7 |
KY | 28 |
MA | 3 |
CT | 1 |
NH | 2 |
Column: State No
Measure | Value |
----------------------
n | 908.0 |
sum | 0.0 |
Mean | 0.0 |
Min | 0.0 |
Max | 0.0 |
Range | 0.0 |
Variance | 0.0 |
Std. Dev | 0.0 |
Column: Scale
Measure | Value |
---------------------------
n | 908.0 |
sum | 567.0 |
Mean | 0.6244493 |
Min | 0.0 |
Max | 4.0 |
Range | 4.0 |
Variance | 0.6272737 |
Std. Dev | 0.79200613 |
Column: Injuries
Measure | Value |
---------------------------
n | 908.0 |
sum | 684.0 |
Mean | 0.75330395 |
Min | 0.0 |
Max | 193.0 |
Range | 193.0 |
Variance | 57.68108 |
Std. Dev | 7.594806 |
Column: Fatalities
Measure | Value |
----------------------------
n | 908.0 |
sum | 48.0 |
Mean | 0.052863438 |
Min | 0.0 |
Max | 16.0 |
Range | 16.0 |
Variance | 0.44262686 |
Std. Dev | 0.6653021 |
Column: Start Lat
Measure | Value |
--------------------------
n | 908.0 |
sum | 34690.984 |
Mean | 38.20593 |
Min | 0.0 |
Max | 48.86 |
Range | 48.86 |
Variance | 22.448586 |
Std. Dev | 4.7379937 |
Column: Start Lon
Measure | Value |
--------------------------
n | 908.0 |
sum | -83613.02 |
Mean | -92.08483 |
Min | -122.946 |
Max | 0.0 |
Range | 122.946 |
Variance | 91.84773 |
Std. Dev | 9.583722 |
Column: Length
Measure | Value |
--------------------------
n | 908.0 |
sum | 3014.49 |
Mean | 3.319923 |
Min | 0.0 |
Max | 45.68 |
Range | 45.68 |
Variance | 28.736567 |
Std. Dev | 5.3606496 |
Column: Width
Measure | Value |
--------------------------
n | 908.0 |
sum | 149778.0 |
Mean | 164.95375 |
Min | 0.0 |
Max | 2640.0 |
Range | 2640.0 |
Variance | 57764.465 |
Std. Dev | 240.34239 |
Mapping operations.
def month = tornadoes.dateColumn("Date").month()
tornadoes.addColumn(month);
tornadoes.columnNames()
[Date, Time, State, State No, Scale, Injuries, Fatalities, Start Lat, Start Lon, Length, Width, Date month]
Sorting by column.
tornadoes.sortOn("-Fatalities")
Descriptive statistics.
tornadoes.column("Fatalities").summary()
Performing totals and sub-totals.
def injuriesByScale = tornadoes.median("Injuries").by("Scale")
injuriesByScale.setName("Median injuries by Tornado Scale")
injuriesByScale
Cross tabulation.
CrossTab.xCount(tornadoes, tornadoes.categoryColumn("State"), tornadoes.shortColumn("Scale"))
Example with Tablesaw
You can fetch data from Quandl and load it directly into Tablesaw
%classpath add mvn com.jimmoores quandl-tablesaw 2.0.0
%import com.jimmoores.quandl.*
%import com.jimmoores.quandl.tablesaw.*
TableSawQuandlSession session = TableSawQuandlSession.create();
Table table = session.getDataSet(DataSetRequest.Builder.of("WIKI/AAPL").build());
// Create a new column containing the year
ShortColumn yearColumn = table.dateColumn("Date").year();
yearColumn.setName("Year");
table.addColumn(yearColumn);
// Create max, min and total volume tables aggregated by year
Table summaryMax = table.groupBy("year").max("Adj. Close");
Table summaryMin = table.groupBy("year").min("Adj. Close");
Table summaryVolume = table.groupBy("year")sum("Volume");
// Create a new table from each of these
summary = Table.create("Summary", summaryMax.column(0), summaryMax.column(1),
summaryMin.column(1), summaryVolume.column(1));
// Add back a DateColumn to the summary...will be used for plotting
DateColumn yearDates = new DateColumn("YearDate");
for(year in summary.column('Year')){
yearDates.append(java.time.LocalDate.of(year,1,1));
}
summary.addColumn(yearDates)
summary
years = summary.column('YearDate').collect()
plot = new TimePlot(title: 'Price Chart for AAPL', xLabel: 'Time', yLabel: 'Max [Adj. Close]')
plot << new YAxis(label: 'Volume')
plot << new Points(x: years, y: summary.column('Max [Adj. Close]').collect())
plot << new Line(x: years, y: summary.column('Max [Adj. Close]').collect(), color: Color.blue)
plot << new Stems(x: years, y: summary.column('Sum [Volume]').collect(), yAxis: 'Volume')
Auto-Translation in BeakerX
Auto-Translation is the act of converting a data structure in one language to another. In the context of data science, the obvious data structures are lists and data frames.
//start with groovy
beakerx.foo = "a groovy value"
a groovy value
//to javascript
%%javascript
beakerx.bar = [23, 48, 7, "from JS"];
beakerx.foo
//back to groovy
beakerx.bar
//to python
%%python
from beakerx import beakerx
beakerx.foo
'a groovy value'
//to scala
%%scala
beakerx.foo
a groovy value
Graphing with BeakerX
Both BeakerX and Tablesaw do a good job of addressing the need to visualize data.
rates = new CSV().read("../doc/resources/data/interest-rates.csv")
def f = new java.text.SimpleDateFormat("yyyy MM dd")
lehmanDate = f.parse("2008 09 15")
bubbleBottomDate = f.parse("2002 10 09")
inversion1 = [f.parse("2000 07 22"), f.parse("2001 02 16")]
inversion2 = [f.parse("2006 08 01"), f.parse("2007 06 07")]
def size = rates.size()
(0 ..< size).each{row = rates[it]; row.spread = row.y10 - row.m3}
OutputCell.HIDDEN
// The simplest chart function with all defaults:
new SimpleTimePlot(rates, ["y1", "y10"])
//scatter plot
def c = new Color(120, 120, 120, 100)
new Plot() << new Points(x: rates.y1, y: rates.y30, displayName: "y1 vs y30") \
<< new Points(x: rates.m3, y: rates.y5, displayName: "m3 vs y5") \
<< new Line(x: rates.m3, y: rates.y5, color: c) \
<< new Line(x: rates.y1, y: rates.y30, color: c)
def ch = new Crosshair(color: Color.gray, width: 2, style: StrokeType.DOT)
// The top plot has 2 lines.
p1 = new TimePlot(yLabel: "Interest Rate", crosshair: ch)
p1 << new Line(x: rates.time, y: rates.m3, displayName: "3 month")
p1 << new Line(x: rates.time, y: rates.y10, displayName: "10 year")
// The bottom plot has an area filled in.
p2 = new TimePlot(yLabel: "Spread", crosshair: ch)
p2 << new Area(x: rates.time, y: rates.spread, color: new Color(120, 60, 0))
// Highlight the inversion intervals
def b1 = new ConstantBand(x: inversion1, color: new Color(240, 100, 100, 55))
def b2 = new ConstantBand(x: inversion2, color: new Color(240, 100, 100, 55))
// Add notation and line for Lehman Bankruptcy.
p1 << new Text(x: lehmanDate, y: 7.5, text: "Lehman Brothers Bankruptcy")
def l1 = new ConstantLine(x: lehmanDate, style: StrokeType.DOT, color: Color.gray)
// Add notation and line for Stocks Nadir.
p1 << new Text(x: bubbleBottomDate, y: 5.75, text: "Stocks Hit Bottom")
def l2 = new ConstantLine(x: bubbleBottomDate, style: StrokeType.DOT, color: Color.gray)
// add the notations and highlight bands to both plots
p1 << l1 << l2 << b1 << b2
p2 << l1 << l2 << b1 << b2
OutputCell.HIDDEN
// Then use a CombinedPlot to get stacked plots with linked X axis.
def c = new CombinedPlot(title: "US Treasuries", initWidth: 1000)
// add both plots to the combined plot, and including their relative heights.
c.add(p1, 3)
c.add(p2, 1)
Integration with D3js
Being able to prototype for the frontend is key for deliverying quickly. The BeakerX integration with D3js is great for this.
def r = new Random()
def nnodes = 100
def nodes = []
def links = []
for (x in (0..nnodes)){
nodes.add(name:"" + x, group:((int) x*7/nnodes))
}
for (x in (0..(int) nnodes*1.15)) {
source = x % nnodes
target = ((int) log(1 + r.nextInt(nnodes))/log(1.3))
value = 10.0 / (1 + abs(source - target))
links.add(source: source, target: target, value: value*value)
}
beakerx.graph = [nodes: nodes, links: links]
OutputCell.HIDDEN
%%javascript
require.config({
paths: {
d3: '//cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min'
}});
%%html
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
%%javascript
beakerx.displayHTML(this, '<div id="fdg"></div>');
var graph = beakerx.graph
var d3 = require(['d3'], function (d3) {
var width = 600,
height = 500;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().distance(30))
.force("charge", d3.forceManyBody().strength(-200))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("y", d3.forceY(width / 2).strength(0.3))
.force("x", d3.forceX(height / 2).strength(0.3));
var svg = d3.select("#fdg")
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate("+[100, 0]+")");
simulation
.nodes(graph.nodes)
.force("link")
.links(graph.links);
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.style("fill", function(d) { return color(d.group); });
node.append("title")
.text(function(d) { return d.name; });
simulation.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
node.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
});
References
Table of keywords
The following table lists the keywords which are defined in Groovy
as | assert | break | case | |
catch | class | const | continue | |
def | default | do | else | |
enum | extends | false | Finally | |
for | goto | if | implements | |
import | in | instanceof | interface | |
new | pull | package | return | |
super | switch | this | throw | |
throws | trait | true | try | |
while |
Groovy but not Java:
as | def | in | trait |
Data types
Primitive data types
byte − represent a byte value. An example is 2
short − represent a short number. An example is 10
int − represent whole numbers. An example is 1234
long − represent a long number. An example is 10000090
float − represent 32-bit floating point numbers. An example is 12.34
double − represent 64-bit floating point numbers which are longer decimal numbers which may be required at times. An example is 12.3456565
char − defines a single character literal. An example is ‘a’
Boolean − represents a Boolean value which can either be true or false
String − text literals which are represented in the form of chain of characters. For example “Hello World”.
In addition to the primitive types, the following object types (sometimes referred to as wrapper types) are allowed −
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
For arbitrary precision artithemetic
java.math.BigInteger
java.math.BigDecimal