A look at the future of JVM languages including Kotlin, Scala, Groovy, and latest Java.
Which language to use ? what are the benefits of higher level abstractions ? and what are the benefits of programming on the JVM ?
23. public class ObjectExample {
private int value;
private String name;
public ObjectExample(int value, String name) {
this.value = value;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public static void main(String[] args) {
ObjectExample object = new ObjectExample(1,"Awesome");
System.out.println("Name " + object.getName() + " Value " + object.getValue());
}
}
Java -> Groovy Objects
class ObjectExample {
int value
String name
}
object = new ObjectExample(value:1,name:"Awesome")
println "Name $object.name Value $object.value"
implicit Getters/Setters
semi colons optional
parentheses optional
interpolated Strings
named properties in Constructor
static void main not needed
variable type optional
default static imports
24. public class ObjectExample {
private int value;
private String name;
public ObjectExample(int value, String name) {
this.value = value;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
Java -> Scala Objects
case class ObjectExample(value: Int, name: String)
25. public class ObjectExample {
private int value;
private String name;
public ObjectExample(int value, String name) {
this.value = value;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
Java 8 -> Java 14 Records
public record ObjectExample(int value, String name)
26. import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Main {
public static void main(String[] args) {
List<Integer> someItems = Arrays.asList(new Integer[]{1, 2, 3, 4});
for (Integer item : someItems) {
System.out.println(item);
}
Map<String, String> someMapping = new HashMap<>();
someMapping.put("ST", "started");
someMapping.put("IP", "in progress");
someMapping.put("DN", "done");
for (Map.Entry<String, String> entry : someMapping.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " => " + value);
}
}
}
Java -> Groovy Collections
def someItems = [1, 2, 3, 4]
someItems.each {
println it
}
def someMapping = ["ST": "started", "IP": "in progress", "DN": "done"]
someMapping.each { key, val ->
println "$key => $val"
}
collection literals
default collection imports
closure parameter def optional (it)
27. import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class JavaSqlExample {
static class Book {
public String name;
public int price;
public Book(String name, int price) {
this.name = name;
this.price = price;
}
}
public static void main(String[] args) throws SQLException{
List<Book> books = new ArrayList<>();
try (Connection con = DriverManager.getConnection("jdbc:h2:mem:")) {
con.prepareStatement("CREATE TABLE books " +
"AS SELECT 'Animal Farm' AS name, 123 AS price").execute();
try (ResultSet rs = con.prepareStatement("SELECT * FROM books").executeQuery()) {
while (rs.next()) {
books.add(new Book(rs.getString("name"), rs.getInt("price")));
}
}
}
books.forEach((book) -> System.out.println("Book " + book.name + " Price - " + book.price));
}
}
Java -> Groovy SQL
def sql = Sql.newInstance "jdbc:h2:mem:"
sql.execute """
CREATE TABLE books
AS SELECT 'Animal Farm' AS name, 123 AS price
"""
sql.rows "SELECT * FROM books" each {
println "Book - $it.name , Price - $it.price"
}
sql.close()
multiline strings
dynamic types
simpli
fi
ed SQL
28. BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
String everything = sb.toString();
} finally {
br.close();
}
Java -> Groovy
everything = new File("file.txt").text
many built in convenience methods
(
fi
les, xml, json, rest, console)
Process p = new ProcessBuilder("ifconfig",
“en0").start();
BufferedReader br = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String line = br.readLine();
while(line != null){
System.out.println(line);
line = br.readLine();
}
println "ifconfig en0".execute().text
29. Groovy Goodness
if ((1.1 + 0.1) == 1.2)
System.out.println("Matches in Groovy, NOT!! in Java");
big decimal by default
execute directly on Unix (#)
#!/usr/bin/env groovy
println("Hello world")
chmod +x helloWorl
d
./helloWorld
@Grab(group='org.springframework', module='spring', version='2.5.6')
import org.springframework.jdbc.core.JdbcTemplate
download dependencies
String.metaClass.shout = {
delegate.toUpperCase()
}
println "Hello!".shout()
add methods to existing classes
return optional
30. String version = "UNKNOWN";
if(computer != null){
Soundcard soundcard = computer.getSoundcard();
if(soundcard != null){
USB usb = soundcard.getUSB();
if(usb != null){
version = usb.getVersion();
}
}
}
Java -> Groovy
version = computer?.getSoundcard()?.getUSB()?.getVersion() ?: "UNKNOWN";
elvis operator (?:)
safe navigation operator (?.)
public List<String> decrypt(List<String> encryptedText) {
return encryptedText.stream()
.map(this::decryptText)
.collect(Collectors.toList());
}
public List<String> decrypt(List<String> encryptedText) {
return encryptedText*.decryptText
}
spread dot operator (*.)
31. Groovy Testing
(Power Asserts)
Condition not satisfied
:
'Grails Goodness' == course.descriptio
n
| |
|
| | Groovy Goodnes
s
| com.mrhaki.blog.Course@3435ec
9
fals
e
4 differences (73% similarity
)
Gr(ails) Goodnes
s
Gr(oovy) Goodness
assert 'Grails Goodness' == course.description
32. Groovy Testing (Spock)
def "addition test "()
{
when: "2 is added to 2"
int sum = 2 + 2
then: "sum should be 4"
sum == 4
}
33. Groovy Testing (Spock)
Parametrized Inputs
def "Data Drive test - minimum of #a and #b is #c"()
{
expect
:
Math.min(a, b) ==
c
where
:
a | b ||
c
3 | 7 || 3
5 | 4 || 4
9 | 9 || 9
}
34. Groovy Testing (Spock+Geb)
Web Application Testing
def "API example (non-Html content) -- health check"() {
given:
go "https://status.github.com/api/status.json"
expect
:
$('pre').text().startsWith('{"status":"good"'
)
}
38. Java 10+ Type Inference
var list = new ArrayList<String>(); // infers ArrayList<String
>
var stream = list.stream(); // infers Stream<String>
39. Java 13+ Switch Expressions
switch (day)
{
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6)
;
case TUESDAY -> System.out.println(7)
;
case THURSDAY, SATURDAY -> System.out.println(8)
;
case WEDNESDAY -> System.out.println(9)
;
}
40. Java 15+ Text Blocks
public String textBlocks()
{
return ""
"
Get busy livin
g
o
r
get busy dying
.
--Stephen King"""
;
}
41. Led to innumerable errors, vulnerabilities, and
system crashes, which have probably caused a
billion dollars of pain and damage in the last forty
years.
Tony Hoare
(on his invention of the null reference)
42. Kotlin - True Null Safety
var a: String = "abc"
a = null // compilation error
44. ▸Steep Learning Curve
▸Compatibility Issues
▸Lackluster IDE Support
▸Negative Market Trend
▸Including Companies moving back to Java (including Twitter)
▸Opinion -> Strong Pass *
SCALA
Rare niches aside (Big Data)
45. GROOVY
▸Easy Learning Curve
▸Strong Industry and IDE Support (JetBrains/Google)
▸Dynamic Typing (a double edged sword)
▸Slowed Adoption
▸Opinion -> Consider (for build scripts and testing)
▸Prefer Gradle over Maven :)
46. ▸Strong Industry and IDE Support
▸Modern Java 19+ features have still no caught up
with alternatives
▸Opinion -> Consider
JAVA 19+ (OR 8)
47. ▸Easy Learning Curve
▸Strong Industry and IDE Support (JetBrains/Google)
▸True Null Safety
▸Gradle Scripts can be written in Kotlin
▸Opinion -> Strong Consider (especially for Android)
KOTLIN