4. @mirocupakDJUG 4
Best practices
• Take advantage of convenience factory methods for collections.
• Immutable collections via of/ofEntries and copies via copyOf.
• Less verbose, no static initializer blocks.
• Create immutable collections by default, only add mutability when needed.
• No need to worry about forgetting references to underlying collections.
• Thread-safe and can be shared freely (no need for defensive copies).
• Good performance.
• Prefer collecting into immutable collections using toUnmodifiableList,
toUnmodifiableSet, toUnmodifiableMap.
• Use toArray to convert collections to arrays.
5. @mirocupakDJUG 5
Antipatterns
• Obtaining collections through other data structures (Arrays.asList,
Stream.of).
• Pulling in external dependencies only to obtain immutable collections (e.g.
Guava and its Immutable*).
• Instance-initializer construct in an anonymous inner class to instantiate
collections.
• Performance over clean APIs ([List, Set, Map].of).
6. @mirocupakDJUG 6
Patterns
• Static factory methods to create objects (of/ofEntries/copyOf).
• Name concisely (convention: of).
• Concrete classes not as part of the public API with static methods on
interfaces returning instances (pattern for implementation flexibility).
• Static import when readability not jeopardized (java.util.Map.entry).
• Tuple wrapper objects and convenience methods to generate them when
multiple varargs needed (Map.ofEntries).
• Converting between types via copyOf.
• Constructor reference as a generating function (array in a toArray call).
• Immutability by default (collections with copies and collectors).
8. @mirocupakDJUG 8
Best practices
• Take advantage of the Stream API to access only certain elements.
• Be aware of StackWalker.Option.
• Don’t resolve classes manually.
• Use to show hidden and reflection frames.
9. @mirocupakDJUG 9
Antipatterns
• Using [Thread, Throwable].getStackTrace() to traverse selected
frames of the execution stack.
• Treating execution stack as text.
• Using strings to represent Class instances.
• Accessing things eagerly when only parts of them are needed.
• Surprising hidden method behaviour (omitting elements of the stack for
performance).
10. @mirocupakDJUG 10
Patterns
• Collections over arrays.
• Leveraging Stream API in API design.
• Choose suitable represetations (don’t model everything as strings).
• Good performance through lazy access via streams.
• Methods accepting functions on streams as parameters to maintain
consistent state and control (walk()).
• Obtaining configured instances via static factory methods parameterized
with enums (getInstance()).
• Work with a security manager (secure access to Class objects).
• Permission checks when constructing instead of using an object.
12. @mirocupakDJUG 12
Best practices
• ProcessHandle is a clean way of obtaining information about processes.
• Take advantage of convenience methods: pid, info, command…
• Trigger actions on process termination via onExit.
• Connect ProcessBuilder with ProcessHandle via toHandle.
13. @mirocupakDJUG 13
Antipatterns
• Accessing process information via MXBeans or OS utilities.
• Pulling in external libraries for simple process management (e.g. Apache
Commons Exec).
• Incomplete APIs - providing functionality to start hard-to-manage resources
without providing the functionality to obtain information about them.
• APIs leading the clients to use non-portable constructs.
14. @mirocupakDJUG 14
Patterns
• Providing convenience methods for commonly used functionality.
• Compact fluent API to access nested information.
• Nested public interfaces to group and organize (ProcessHandle.Info).
• Using convenient static factory methods to obtain instances
(ProcessHandle.[current, of, allProcesses]).
• Returning streams instead of collections to streamline lazy processing of
many elements (allProcesses, children, descendants…).
• Returning CompletableFuture instances in asynchronous APIs
(onExit).
• Providing adapters via to* methods (toHandle).
16. @mirocupakDJUG 16
Best practices
• Clear organization: HttpClient, HttpRequest, HttpResponse.
• HttpURLConnection is not pleasant to use.
• The new client API is versatile, flexible and clean.
• Prefer functionality in the JDK to external libraries.
17. @mirocupakDJUG 17
Antipatterns
• Using HttpURLConnection directly.
• Inconsistent capitalization (HttpURLConnection).
• Overly abstract and general APIs (URLConnection).
• Unclear conceptual API model (URL).
• Type casting needed to obtain the right instance (openConnection).
• Using strings where methods or enums would be more practical
(setRequestMethod(“GET”)).
• Requiring the client to use I/O boilerplate (BufferedReader/
InputStreamReader/InputStream…).
18. @mirocupakDJUG 18
Antipatterns
• Mandatory blocking network I/O.
• Side effects and hidden assumptions (getInputStream).
• Inconsistent behaviour across APIs (URLConnection vs. Socket).
19. @mirocupakDJUG 19
Patterns
• Clear separation of concepts at the class level (HttpClient,
HttpRequest, HttpResponse).
• Builder.
• Asynchronous via CompletableFuture.
• Clear and consistent naming.
• Convenience methods to access commonly used features (statusCode,
body).