4. Goal
Learn about key enhancements on the JDK tools since
Java 17 so that you can efficiently code, deploy and
monitor your applications.
Image by Efraimstochter from Pixabay
6. Compiling and Launching a Java Program
IDE javac java
.java source
file
bytecode .class
file
Program running
7. Standard Compiler Optimizations
☕ Literal constants are folded.
☕ String concatenation is folded.
☕ Constant fields are inlined.
☕ Dead code branches are eliminated.
☕ These do not require any flag and are part of the compiler specification before JDK 17.
8. String Concatenation Order of Operations (1)
☕ Strategy before JDK 19
public class Example {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("foo");
System.err.println("" + builder + builder.append("bar"));
}
}
9. String Concatenation Order of Operations (2)
☕ Strategy before JDK 19
public class Example {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("foo");
System.err.println("" + builder + builder.append("bar"));
// print foobarfoobar
}
}
10. String Concatenation Order of Operations (3)
☕ After JDK 19 evaluates each argument, eagerly convert it to a string, in left-to-right order.
public class Example {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("foo");
System.err.println("" + builder + builder.append("bar"));
// print foofoobar
}
}
[Indy String Concat Changes Order of Operations — JDK-8273914]
11. Warnings On Lossy Conversions (1)
☕ Evaluation error before JDK 20
public class LintExample {
public static void main(String[] args) {
long value = 5L;
long b = value + 0.1 * 3L;
}
}
12. Warnings On Lossy Conversions (2)
☕ Evaluation error before JDK 20
public class LintExample {
public static void main(String[] args) {
long value = 5L;
long b = value + 0.1 * 3L;
// incompatible types: possible lossy conversion
// from double to long
}
}
13. Warnings On Lossy Conversions (3)
☕ Evaluation before JDK 20
public class Example {
public static void main(String[] args) {
long b = 5L;
b += 0.1 * 3L;
//no error
}
}
14. Warnings On Lossy Conversions (4)
☕ Evaluation after JDK 20
$ javac Example.java -Xlint:all
> Example.java:4: warning: [lossy-conversions] implicit cast > from
double to long in compound assignment is possibly lossy
> b += 0.1 * 3L;
^
> 1 warning
[Warn compound assignment is possibly lossy — JDK-8244681]
15. Warnings about possible this escapes (1)
☕ DO NOT call overridable methods from a constructor!
public class LintExample {
public LintExample() {
System.out.println(this.hashCode());
}
public static void main(String[] args) {
new LintExample();
// all good
}
}
16. Warnings about possible this escapes (2)
☕ Since JDK 21 The compiler has a new -Xlint:this-escape key
$ javac LintExample.java -Xlint:[all|this-escape]
> LintExample.java 3: warning: [this-escape] possible 'this' escape
> before subclass is fully initialized
> System.out.println(this.hashCode());
^
> 1 warning
17. Towards Enhanced Usability
☕ Since JDK 11 you have single-file execution java HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
18. Launch Java Applications Easier
☕ Since JDK 11 you have single-file execution java HelloWorld.java
☕ JEP 458 ㉒ Run a Java program supplied as multiple files
java -cp‘*’ HelloWorld.java
// HelloWorld.java
class HelloWorld {
public static void main(String[] args) { Helper.run();}
}
// Helper.java
class Helper {
static void run() { System.out.println("Hello World!"); }
}
20. Goals for API Documentation
☕ Helps with product maintenance.
☕ Technical users can understand your APIs goals.
☕ Can increase awareness/adoption of your software.
☕ Third-party developers can start quickly by trying out API examples.
22. Inserting Fragments Of Source Code In
Documentation
☕ Wrap code examples inside <pre> and {@code ...}
☕ Automatically escape special characters with {@code ...}
☕ No control over indentation
☕ No code highlighting
23. /**
* <p>Java class for user complex type.
* <p/>
* <p>The following schema fragment specifies the expected content for the User class.
* <p/>
* <pre> {@code
* <complexType name="user">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
* <element name="email" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="firstName” type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="userName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* }
* </pre>
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {"id", "email", "firstName", "lastName","userName”})
public class User {
//..
24. /**
* <p>Java class for user complex type.
* <p/>
* <p>The following schema fragment specifies the expected content for the User class.
* <p/>
* <pre> {@code
* <complexType name="user">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
* <element name="email" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="firstName” type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="userName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* }
* </pre>
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {"id", "email", "firstName", "lastName","userName”})
public class User {
//..
25.
26. Elegant Inclusion Of Code Examples
☕ JEP 413 introduced {@snippet ...} tag in JDK 18
☕ A better presentation of the targeted code examples via regions.
☕ Control code via @highlight, @replace, @link tags and using region or region=name.
27. /**
* <p>Java class for user complex type.
* </p>
* <p>The following schema fragment specifies the expected content for the User class.
* </p>
* {@snippet lang=xml :
* //@start region="type"
* <complexType name="user">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* //@highlight region="element" regex="name=.w+."
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
* <element name="email" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="firstName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="userName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* //@end region="element"
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* //@end region="type"
* }
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {"id", "email", "firstName", "lastName","userName”})
public class User {
28. /**
* <p>Java class for user complex type.
* </p>
* <p>The following schema fragment specifies the expected content for the User class.
* </p>
* {@snippet lang=xml :
* //@start region="type"
* <complexType name="user">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* //@highlight region="element" regex="name=.w+."
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
* <element name="email" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="firstName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="userName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* //@end region="element"
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* //@end region="type"
* }
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {"id", "email", "firstName", "lastName","userName”})
public class User {
29.
30. Efficient Inclusion Of Code Examples
☕ JEP 413 introduced {@snippet ...} tag in JDK 18
☕ A better presentation of the targeted code examples via regions.
☕ Control code via @highlight, @replace, @link tags and using region or region=name.
☕ The tag accepts separate files that contain the content of the snippet.
$ javadoc # other options...
--snippet-path ./src/xml User.java
31. /**
* <p>Java class for user complex type.
* </p>
* <p>The following schema fragment specifies the expected content for the User class.
* </p>
* {@snippet file="user.xml" lang=xml}
*
*/
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {"id", "email", "firstName", "lastName","userName”})
public class User {
//..
32. /**
* <p>Java class for user complex type.
* </p>
* <p>The following schema fragment specifies the expected content for the User class.
* </p>
* {@snippet file="user.xml" lang=xml}
*
*/
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {"id", "email", "firstName", "lastName","userName”})
public class User {
//..
33. Benefit of Interactive Documentation
☕ Configure the --add-script <file> option of javadoc.
$ cat interact.js
> alert("Okey-dokey! Get ready to move your fingers!");
$ javadoc # options...
$ --add-script interact.js User.java
☕ Use the option to add multiple scripts in your generated documentation.
[Add scripts to generated documentation— JDK-8275786]
35. Fast Prototyping Java Code with jshell
☕ Quickly try, debug and learn Java and its APIs.
☕ Experiment with Java by bypassing the compile stage.
☕ Get immediate feedback on your code.
☕ Exposes a programmatic API
36. Highlighting Deprecated Elements,
Variables And Keywords
jshell> var check = new Boolean("true");
| Warning:
| Boolean(java.lang.String) in java.lang.Boolean has been
| deprecated and marked for removal
| var check = new Boolean("true");
| ^-----------------^
check ==> true
[jshell outlines deprecated elements ⑲ — JDK-8274148]
37. JDK Tool Access in jshell
☕ jshell supports loading scripts.
☕ Scripts can be local files or one of the predefined scripts.
☕ Scripts may hold any valid code snippets or jshell commands.
38. Predefined jshell Scripts
Predefined script Description
DEFAULT Loads the default entries, which are commonly used as imports.
JAVASE Imports all Java SE packages.
PRINTING Defines print, println, and printf as jshell methods
for use within the tool.
TOOLING㉑ Defines javac, jar, and other methods for running JDK tools
via their command-line interface within the jshell tool.
39. Loading TOOLING script
☕ When you start jshell
$ jshell TOOLING
☕ Inside a jshell session
jshell> /open TOOLING
40. Using the TOOLING script
☕ Check available tools
jshell> tools()
☕ Execute a tool command in a jshell session
jshell> run("javac", "-version")
javac 21
[JDK tools in jshell ㉑ — JDK-8306560]
41. What tool would you use for local
prototyping, testing or debugging a
client-server setup?
[Introducing jwebserver ⑱ — JEP 408]
42. Use Cases for jwebserver (1)
☕ Web development testing, to simulate locally a client-server setup.
$ jwebserver
> Binding to loopback by default. For all interfaces use "-b 0.0.0.0"
> or "-b ::".
> Serving /cwd and subdirectories on 127.0.0.1 port 8000
> URL: http://127.0.0.1:8000/
43. Use Cases for jwebserver (2)
☕ Web development testing, to simulate locally a client-server setup.
☕ Use static files as API stubs for web-service prototyping or application testing.
$ jwebserver -p 9000
> Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or
> "-b ::". Serving /example and subdirectories on 127.0.0.1 port 9000
> URL http://127.0.0.1:9000/
> 127.0.0.1 -- [09/Feb/2024:3:02:05 +0200] "GET /api/a1.json HTTP/1.1" 200
> 127.0.0.1 -- [09/Feb/2024:3:02:06 +0200] "GET /api/a2.json HTTP/1.1" 200
44. Use Cases for jwebserver (3)
☕ Web development testing, to simulate locally a client-server setup.
☕ Use static files as API stubs for web-service prototyping or application testing.
☕ Search a directory on a remote server from your local machine.
$ jwebserver -b 0.0.0.0
> Serving /work and subdirectories on 0.0.0.0 (all interfaces) port 8000
> URL http://192.168.178.41:8000/
45. Use Cases for jwebserver (4)
☕ Web development testing, to simulate locally a client-server setup.
☕ Web-service or application testing
☕ Search a directory on a remote server from your local machine.
☕ Great for learning purposes.
46. Working With The Simple Web Server API
$jshell
jshell> var server = SimpleFileServer.createFileServer(new InetSocketAddress(8080),
...> Path.of("/some/path"), OutputLevel.VERBOSE);
jshell> server.start()
The SimpleFileServer class supports the creation of
☕ file server
☕ file handler
☕ an output filter
48. Intro to jpackage
☕ Packages self-contained Java applications.
☕ Prior JDK19, installing a jpackaged app was system-wide.
☕ For modular applications, jpackage will automatically run jlink and generate a runtime
with the modules needed.
49. Using jpackage
jpackage --input target/ --name JDemoApp --main-jar JDemoApp.jar
--main-class org.example.JDemoApp --type app-image
JDemoApp.app/
Contents/
Info.plist
MacOS/ //Application launchers
JDemoApp
Resources/ // Icons, etc.
app/
JDemoApp.cfg //Configuration info, made by jpackage
JDemoApp.jar //JAR file, copied from the --input directory
runtime/ //Java runtime image
50. Installation of a packaged application after
JDK 19
Application launcher will look up the .cfg file in user-specific directories.
Linux
~/.local/${PACKAGE_NAME}
~/.${PACKAGE_NAME}
macOS
~/Library/Application Support/${PACKAGE_NAME}
Windows
%LocalAppData%%PACKAGE_NAME%
%AppData%%PACKAGE_NAME%
# ${PACKAGE_NAME} and %PACKAGE_NAME% refer to jpackaged application name.
51. Installation of a jpackaged application
after JDK 19
Application launcher will look up the .cfg file:
☕ In user-specific directories.
☕ From the installation directory if .cfg file is not found.
☕ From the application image directory if the application launcher is executed from that location.
53. Updated Options for keytool
☕ Since JDK 18, you can check the version of keytool and jarsigner.
$ keytool -version & jarsigner -version
[1] 83711 jarsigner 21 keytool 21
[Add -version option to keytool and jarsigner ⑱ — JDK-8272163]
54. Updated Options for keytool
As of JDK 21, keytool warns you when using weak password-based encryption algorithms via:
☕ -genseckey option
☕ -importpass option
[keytool warns about weak PBE algorithms ㉑ — JDK-8286907]
55. Detecting Weak Password-Based
Encryption Algorithms
$ keytool -genseckey -alias secret -keypass changeit
-keyalg RC4 -keysize 128 -keystore example.p12
-storepass changeit -storetype PKCS12 -v
> Generated 128-bit ARCFOUR secret key [Storing example.p12]
> Warning:
> The generated secret key uses the ARCFOUR algorithm which
> is considered a security risk.
56. Updated Options for jarsigner
☕ As of JDK 19, specify the classpath for providers via –providerPath
$ jarsigner -keystore keystore -storetype CUSTOMKS
-providerPath /path/to/test.myks
-providerClass my.custom.AnotherProvider signed.jar mykey
☕ The options -altsigner and -altsignerpath have been removed in JDK 21.
[Add -providerPath option to jarsigner ⑲ — JDK-8281175]
58. Monitoring Java Applications
Technology Goal
JDK Flight Recorder (JFR) Collects diagnostic and profiling data about a running
Java application.
JFR Event Streaming API API for the continuous consumption of JFR data on disk.
JDK Mission Control (JMC) A set of tools for managing, monitoring, profiling, and
troubleshooting Java applications.
59. New jfr view Command
☕ Start JFR a recording via -XX:StartFlightRecording or jcmd.
$ java -XX:StartFlightRecording -jar imaging.jar
☕ Use the PID or jar name in the command
☕ Use jps JDK tool to list all running Java processes (PID).
[JFR view command ㉑ — JDK-8306704]
60. jfr view Command Example
$ jcmd imaging.jar JFR.view hot-methods
30598:
Java Methods that Executes the Most
Method Samples Percent
--------------------------------------------------------------------- ------- -------
org.springframework.boot.loader.jar.JarFileEntries.sort(int, int) 1 33,33%
jdk.internal.util.ArraysSupport.signedHashCode(int, byte[], int, int) 1 33,33%
java.net.URLStreamHandler.toExternalForm(URL) 1 33,33%
Timespan: 15:46:40 - 15:56:40
61. JFR Event for Finalization
jdk.FinalizerStatistics
☕ Identifies classes at runtime that use finalizers.
☕ No event is sent if java --finalization=disabled.
☕ Enabled by default in the default.jfc and profile.jfc JFR configuration files.
☕ Disable via
$ jfr configure jdk.FinalizerStatistics#enabled=false #or
$ java -XX:StartFlightRecording:settings=none,+jdk.FinalizerStatistics#enabled=false
[A finalization JFR event — JDK-8266936]
62. Recording Initial Security Properties with JFR
jdk.InitialSecurityProperty cryptographic event.
☕ Enabled by default in the default.jfc and profile.jfc JFR configuration files.
☕ Disable via
$ jfr configure jdk.InitialSecurityProperty#enabled=false
$ #or on launch
$ java -XX:StartFlightRecording:settings=none,+jdk.InitialSecurityProperty#enabled=false
63. Recording Details About Security Provider
Instance Requests
jdk.SecurityProviderService cryptographic event
☕ Disabled by default.
☕ Records details about java.security.Provider.getService(…) calls.
☕ Can be enabled via:
$ jfr configure jdk.SecurityProviderService#enabled=true or
$ java -XX:StartFlightRecording:settings=none,+jdk.SecurityProviderService#enabled=true
64. Graph Views for Performance Analysis
and Monitoring
☕ The Graph View was updated to allow limiting the number of nodes displayed.
☕ Focus on most impactful nodes by using smart pruning.
☕ Example use case: focus on how often a specific method is ran based on sampling.
Open JFR Recording -> Method Profiling -> Select method -> Graph View
65.
66. Flame View Graphs for Performance
Analysis and Monitoring
☕ Flame View has options that limit the data displayed on the view.
☕ In the Samples drop-down, select either Allocation Size, Sample Weight or TLAB Size.
☕ Example use case: visualize where your program is spending its memory.
Open JFR Recording -> Memory -> Flame View
67.
68. New Dependency View
☕ The Dependency View shows the relationships between packages within a stack trace.
☕ Visualize dependencies as a chord graph, a circle showing how packages call one another.
☕ A chord graph has thicker lines to represent stronger connections.
☕ Example use case: check dependency view for classes in Memory page.
Open JFR Recording -> Memory -> Select Class -> Dependency View
69.
70. Stay Tuned for More
Inside.jav
a
Dev.jav
a
youtube.com/java
71. Useful Links
☕ Programmer’s Guide to Snippets: https://docs.oracle.com/en/java/javase/21/javadoc/programmers-guide-snippets.html
☕ Java 21 Tool Enhancements: Better Across the Board #RoadTo21 https://www.youtube.com/embed/nFJBVuaIsRg
☕ Using Jshell API https://inside.java/2022/11/21/jshell-java-source-browser/
☕ Christian Stein’s article on jshell tooling https://sormuras.github.io/blog/2023-03-09-jshell-tooling
☕ Julia Boes article on more advanced jwebserver usage https://inside.java/2021/12/06/working-with-the-simple-web-server/
☕ JEP 408 on jwebserver https://openjdk.org/jeps/408
☕ More on jpackage: https://dev.java/learn/jvm/tool/jpackage/
☕ Package a JavaFX application as a native executable https://inside.java/2023/11/14/package-javafx-native-exec/
☕ Stack Walker ep 2 on JFR https://inside.java/2023/05/14/stackwalker-02/
☕ Monitoring Java Application Security with JDK tools and JFR Events: https://dev.java/learn/security/monitor/