HeadtowardJava14andJava15
KUBOTAYuji
LINECorporation
LINEDeveloperMeetup#65
KUBOTAYuji(@sugarlife)
Kafkaplatformteam@LINE
JVMmania,IcedTeacommitter/OpenJDKAuthor
JavaOne2014/2016/2017,WEB+DB「DivetoJava」
https://www.slideshare.net/YujiKubota/
2
WhatIwilltalk
NewfeaturesandchangesavailablefromJava14/15
MainlyaboutJVMandtools
WhatIwillnottalk
Incompatibility
3
Disclaimer
I'vetestedthecontentsofthisdocumentbyJDK14.0.2andJDK15
(build32)whichareavailableon jdk.java.net asmuchaspossible,
butnotallofthemhavebeentested,sopleasedoanoperation
confirmationbeforeyouattempttomodifyyourcode.
IconfirmedtheJDKimplementationby hg.openjdk.java.net/jdk-
updates/jdk14u and jdk/jdk .
4
Java14
16JavaEnhancementProposals(JEP)
155Compatibility&SpecificationReviews(CSR)
Java15
14JavaEnhancementProposals(JEP)
127Compatibility&SpecificationReviews(CSR)
5
Language/APIchanges
Java14
305:PatternMatchingforinstanceof(Preview)
352:Non‑VolatileMappedByteBuffers
359:Records(Preview)
361:SwitchExpressions(Standard)
368:TextBlocks(SecondPreview)
370:Foreign‑MemoryAccessAPI(Incubator)
Java15
360:SealedClasses(Preview)
371:HiddenClasses
373:ReimplementtheLegacyDatagramSocketAPI
375:PatternMatchingforinstanceof(SecondPreview)
378:TextBlocks
383:Foreign‑MemoryAccessAPI(SecondIncubator)
384:Records(SecondPreview)
385:DeprecateRMIActivationforRemoval
6
305:PatternMatchingforinstanceof(Preview)
Before
if (obj instanceof Double) {
Double d = (Double) obj;
// Processing with d
}
After
if (obj instanceof Double d) {
// Processing with d
}
thesamewayon switch (Undetermineddate)
switch (obj) {
case Integer i:
// want to do when Integer
case Double d:
// want to do when Double
}
NofurtherchangeinJava15(SecondPreview). 7
359:Records(Preview)
Newtypetocarryadata(like@Value(Lombok))
public record TestRecord(String s, int i) {}
public record TestRecord(String s, int i) {
private final String s;
private final int i;
String s() { return s; }
int i() {return i;}
TestRecord(String s, int i) {
this.s = s;
this.i = i;
}
// toString(), equals(), hashCode()
}
8
368:TextBlocks(SecondPreview)
AddEscape  (linebreak), s (space)
var textblock = """
Duke is 
cute s
""";
var textblock = "Duke is cute ";
NofurtherchangeinJava15(Standard).
9
370:Foreign‑MemoryAccessAPI(Incubator)
383:Foreign‑MemoryAccessAPI(SecondIncubator)
non‑heap
allocateDirect :upto2G( Integer.MAX_VALUE )perobject
JavaNativeInterface:managememorybyyourself
Unsafe.allocateMemory() :potentialremovewithoutwarning
VarHandle intHandle = MemoryHandles.varHandle(int.class,
ByteOrder.nativeOrder());
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
MemoryAddress base = segment.baseAddress();
for (int i = 0; i < 25; i++) {
intHandle.set(base.addOffset(i * 4), i);
}
}
--add-modules jdk.incubator.foreign
10
360:SealedClasses(Preview)
Newtypetorestrictwhichotherclasses/interfacesmay
extend/implementthem
public sealed class Shape
permits com.example.polar.Circle,
com.example.quad.Rectangle,
com.example.quad.simple.Square {...}
11
371:HiddenClasses
Protectdynamicclassesagainstunpredictableaccess
cannotfindbybytecodelinkageand Class::forName ,
Classloader::loadClass
Normalclasses
ClassLoader::defineClass
Hiddenclasses
MethodHandles.Lookup#defineHiddenClass(byte[]
bytes, boolean initialize,
MethodHandles.Lookup.ClassOption... options)
Generatesahiddenclassfromthebyte[]andreturnsa
lookup objectwithreflectiveaccess
This lookup objectistheonlywaytogetthehidden
Classobject
12
Others
Java14
373:ReimplementtheLegacyDatagramSocketAPI
ContinuingTasksfromJava13
352:Non‑VolatileMappedByteBuffers
ByteBufferforNVM:Non‑VolatileMemory
Java15
385:DeprecateRMIActivationforRemoval
Deperecate java.rmi.activation packageandrelated
class/interface
rmid toolwillemitawarningmessage
13
JVMbehaviorchanges(exceptGC)
Java14
358:HelpfulNullPointerExceptions
Java15
374:DisableandDeprecateBiasedLocking
14
358:HelpfulNullPointerExceptions
$ java Sample
Exception in thread "main" java.lang.NullPointerException
at Sample.main(Sample.java:4)
15
4: String name = person.getName().toUpperCase();
public class Sample {
public static void main(String... args){
Person person = new Person();
String name = person.getName().toUpperCase();
}
static class Person {
String name = null;
Person() {
}
String getName() {
return name;
}
}
}
16
4: String name = person[i][j][k] // <= Nullable * 4
.getPersonalInformation() // <= Nullable
.getName() // <= Nullable
.getFamilyName() // <= Nullable
.toUpperCase(); // <= Nullable
17
-XX:+ShowCodeDetailsInExceptionMessages
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "String.toUpperCase()" // When
because the return value of "Sample$Person.getName()" is null // What
$ java -XX:+ShowCodeDetailsInExceptionMessages Sample
Exception in thread "main" java.lang.NullPointerException: Cann
at Sample.main(Sample.java:4)
18
Case:localvariable
3: String[] names = null;
4: names[1].toLowerCase();
$ java -XX:+ShowCodeDetailsInExceptionMessages LocalStringArray
Exception in thread "main" java.lang.NullPointerException:
Cannot load from object array // When
because "<local1>" is null // What
at LocalStringArray.main(LocalStringArray.java:4)
$ javac -g LocalStringArray.java // Add all debugging information
$ java -XX:+ShowCodeDetailsInExceptionMessages LocalStringArray
Exception in thread "main" java.lang.NullPointerException:
Cannot load from object array // When
because "names" is null // What
at LocalStringArray.main(LocalStringArray.java:4)
19
Concerns
Concernsaboutaddingdebugginginfomartion
classfilesize
reverseengineering
ConcernsaboutHelpfullNPE
performance
20
374:DisableandDeprecateBiasedLocking
BiasedlockingwasintroducedtoHotSpotVMtoreduceoverhead
ofuncontentedlocking
java.util.Vector sinceJava1.0
java.util.Collections sinceJava1.2
java.util.concurrent sinceJava5(1.5)
-XX:-UseBiasedLocking
21
GarbageCollectorchanges
Java14
345:NUMA‑AwareMemoryAllocationforG1
363:RemovetheConcurrentMarkSweep(CMS)GarbageCollector
364:ZGConmacOS
365:ZGConWindows
366:DeprecatetheParallelScavenge+SerialOldGCCombination
Java15promotesthefollowingexperimentalcollectorsasstandardfeature.
377:ZGC:AScalableLow‑LatencyGarbageCollector
379:Shenandoah:ALow‑Pause‑TimeGarbageCollector
22
345:NUMA‑AwareMemoryAllocationforG1
NUMAandG1GC
-XX:+UseNUMA
23
363:RemovetheConcurrentMarkSweep(CMS)Garbage
Collector
Goodbye -XX:+UseConcMarkSweepGC
Ifyousetaboveoption,JVMwilllaunchwithDefaultGC
YoushouldspecifyGCalgorthimclearly
OpenJDK 64-Bit Server VM warning:
Ignoring option UseConcMarkSweepGC;
support was removed in 14.0
24
364:ZGConmacOS&JEP365:ZGConWindows
ZGC
ExperimentalfeatureforLinuxsinceJava11
ProductionfeaturesinceJava15(JEP377)
PorttomacOSandWindows
HBaseteamevaluatedZGCwithJava11
https://engineering.linecorp.com/ja/blog/run‑hbase‑on‑
jdk11/
25
366:DeprecatetheParallelScavenge+SerialOldGC
Combination
-XX:+UseParallelGC -XX:-UseParallelOldGC
26
Tools
Java14
343:PackagingTool(Incubator)
349:JFREventStreaming
27
343:PackagingTool(Incubator)
jpackage :ToolsforcreatingJavaapplicationinstallersonLinux,
MacandWindows
NeedtoinstallWiXtoolsforWindows
TheAPIsthistoolusesareincubator
Createcustomruntimeimagebyjlink‑>createinstallerby
jpackage‑>providesforusers
28
Basicusage
$ jpackage --name sample --input <directory_includes_jar> 
--main-jar sample.jar --main-class Sample
$ ls sample-*
sample-1.0.dmg
Withcustomruntimeimage:
# Show ependent modules
$ jdeps -summary Sample.class
Sample.class -> java.base
Sample.class -> java.desktop
# Create runtime image that consists only of dependent modules
$ jlink --add-modules java.base,java.desktop --output image
# Create installer with custom runtime image
$ jpackage --name sample --input <directory_includes_jar> 
--main-jar sample.jar --main-class Sample --runtime-image image
29
349:JFREventStreaming
CollecteventsfromlocalJavaprocess
import java.time.Duration;
import jdk.jfr.consumer.RecordingStream;
public class JFRSample {
public static void main(String... args) {
try (RecordingStream rs = new RecordingStream()) {
// Enable events JVM will collect periodically
rs.enable("jdk.CPULoad")
.withPeriod(Duration.ofSeconds(10));
// Registers consumer to perform on event matching a name
rs.onEvent("jdk.CPULoad", System.out::println);
// Nothing happens when you specify an uncollected event
rs.onEvent("jdk.SafepointCleanup", System.out::println);
rs.start();
}
}
}
30
$ java Sample
jdk.CPULoad {
startTime = 18:30:06.225
jvmUser = 1.96%
jvmSystem = 0.10%
machineTotal = 16.56%
}
jdk.CPULoad {
startTime = 18:30:07.239
jvmUser = 0.26%
jvmSystem = 0.03%
machineTotal = 16.60%
}
:
31
AvailableEvents
built‑in:matadata.xml
ThreadPark,JavaMonitor,ClassLoad,PromotionFailed,...
canimplementbyextending jdk.jfr.Event sinceJava9
AvailableConfigurations
default
profile
32
Useconfigurationinsteadofenablingeventsbyyourself
import jdk.jfr.Configuration;
import jdk.jfr.consumer.EventStream;
import jdk.jfr.consumer.RecordingStream;
public class JFRSample {
public static void main(String... args) throws Exception {
try (RecordingStream rs = new RecordingStream(
// Set "default" or "profile"
Configuration.getConfiguration("default"))) {
// Can register action on events JVM collects by "default"
rs.onEvent("jdk.CPULoad", System.out::println);
rs.start();
}
}
}
33
CollecteventsfromremoteJavaprocessviaRepository
-XX:FlightRecorderOptions=repository=/path/to
# Launch jshell with enabling JFR
$ jshell -J-XX:StartFlightRecording=maxage=15m,settings=default
Started recording 1.
:
# Check repository path of targeted Java process (jshell)
$ jcmd $(pgrep jshell) JFR.configure
14006:
Current configuration:
Repository path: /private/var/folders/wm/dz3pkjf11hb1mph16365hj1h0000gp/T/2020_
:
34
Openstreamwithrepositorypath
import java.io.IOException;
import java.nio.file.Path;
import jdk.jfr.consumer.EventStream;
public class JFRRemoteSample {
public static void main(String... args) throws IOException {
// Pass repository path via argument
try (EventStream es = EventStream
.openRepository(Path.of(args[0]))) {
// Method Profiling Sample event
es.onEvent("jdk.ExecutionSample", System.out::println);
es.start();
}
}
}
$ java JFRRemoteSample /private/(snip)/2020_05_14_18_57_15_15902
jdk.ExecutionSample {
startTime = 19:09:55.345
sampledThread = "JFR Periodic Tasks" (javaThreadId = 13)
state = "STATE_RUNNABLE"
stackTrace = [
jdk.jfr.internal.PlatformRecorder.periodicTask() line: 474
jdk.jfr.internal.PlatformRecorder.lambda$startDiskMonitor$1() line:
jdk.jfr.internal.PlatformRecorder$$Lambda$52.1546693040.run()
java.lang.Thread.run() line: 832
]
}
35
ConcernaboutJFRandOOME
LeakProfilercannotobtaininfromationduetoshutdown
Shouldset -XX:+HeapDumpOnOutOfMemoryError
36
Otherchanges
Java14
362:DeprecatetheSolarisandSPARCPorts
Java15
339:Edwards‑CurveDigitalSignatureAlgorithm(EdDSA)
372:RemovetheNashornJavaScriptEngine
381:RemovetheSolarisandSPARCPorts
37
HeadtowardJava14andJava15
KUBOTAYuji
LINECorporation
LINEDeveloperMeetup#65
38

Head toward Java 14 and Java 15 #LINE_DM