Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions content/collections/reverse-list-iteration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": 96,
"slug": "reverse-list-iteration",
"title": "Reverse list iteration",
"category": "collections",
"difficulty": "beginner",
"jdkVersion": "21",
"oldLabel": "Java 8",
"modernLabel": "Java 21+",
"oldApproach": "Manual ListIterator",
"modernApproach": "reversed()",
"oldCode": "for (ListIterator<String> it =\n list.listIterator(list.size());\n it.hasPrevious(); ) {\n String element = it.previous();\n System.out.println(element);\n}",
"modernCode": "for (String element : list.reversed()) {\n System.out.println(element);\n}",
"summary": "Iterate over a list in reverse order with a clean for-each loop.",
"explanation": "The reversed() method from SequencedCollection returns a reverse-ordered view of the list. This view is backed by the original list, so no copying occurs. The enhanced for loop syntax makes reverse iteration as readable as forward iteration.",
"whyModernWins": [
{
"icon": "📖",
"title": "Natural syntax",
"desc": "Enhanced for loop instead of verbose ListIterator."
},
{
"icon": "⚡",
"title": "No copying",
"desc": "reversed() returns a view — no performance overhead."
},
{
"icon": "🧩",
"title": "Consistent API",
"desc": "Works on List, Deque, SortedSet uniformly."
}
],
"support": {
"state": "available",
"description": "Widely available since JDK 21 LTS (Sept 2023)"
},
"prev": "collections/stream-toarray-typed",
"next": "collections/unmodifiable-collectors",
"related": [
"collections/sequenced-collections",
"collections/immutable-list-creation",
"streams/stream-tolist"
]
}
2 changes: 1 addition & 1 deletion content/collections/stream-toarray-typed.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"description": "Widely available since JDK 8 (March 2014)"
},
"prev": "collections/collectors-teeing",
"next": "collections/unmodifiable-collectors",
"next": "collections/reverse-list-iteration",
"related": [
"collections/collectors-teeing",
"collections/map-entry-factory",
Expand Down
2 changes: 1 addition & 1 deletion content/collections/unmodifiable-collectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"state": "available",
"description": "Widely available since JDK 10 (March 2018)"
},
"prev": "collections/stream-toarray-typed",
"prev": "collections/reverse-list-iteration",
"next": "strings/string-isblank",
"related": [
"collections/immutable-map-creation",
Expand Down
44 changes: 44 additions & 0 deletions content/io/file-memory-mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": 97,
"slug": "file-memory-mapping",
"title": "File memory mapping",
"category": "io",
"difficulty": "advanced",
"jdkVersion": "22",
"oldLabel": "Java 8",
"modernLabel": "Java 22+",
"oldApproach": "MappedByteBuffer",
"modernApproach": "MemorySegment with Arena",
"oldCode": "try (FileChannel channel =\n FileChannel.open(path,\n StandardOpenOption.READ,\n StandardOpenOption.WRITE)) {\n MappedByteBuffer buffer =\n channel.map(\n FileChannel.MapMode.READ_WRITE,\n 0, (int) channel.size());\n // Limited to 2GB\n // Freed by GC, no control\n}",
"modernCode": "FileChannel channel =\n FileChannel.open(path,\n StandardOpenOption.READ,\n StandardOpenOption.WRITE);\ntry (Arena arena = Arena.ofShared()) {\n MemorySegment segment =\n channel.map(\n FileChannel.MapMode.READ_WRITE,\n 0, channel.size(), arena);\n // No size limit\n // ...\n} // Deterministic cleanup",
"summary": "Map files larger than 2GB with deterministic cleanup using MemorySegment.",
"explanation": "The Foreign Function & Memory API (JEP 454) introduces MemorySegment for safe and efficient memory access. Unlike MappedByteBuffer, MemorySegment supports files larger than 2GB (Integer.MAX_VALUE), provides deterministic cleanup via Arena, and offers better performance with modern hardware.",
"whyModernWins": [
{
"icon": "📏",
"title": "No size limit",
"desc": "Map files larger than 2GB without workarounds."
},
{
"icon": "🔒",
"title": "Deterministic cleanup",
"desc": "Arena ensures memory is freed at scope exit, not GC time."
},
{
"icon": "⚡",
"title": "Better performance",
"desc": "Aligned with modern memory models and hardware."
}
],
"support": {
"state": "available",
"description": "Available since JDK 22 (March 2024)"
},
"prev": "io/try-with-resources-effectively-final",
"next": "io/files-mismatch",
"related": [
"io/http-client",
"io/reading-files",
"io/writing-files"
]
}
2 changes: 1 addition & 1 deletion content/io/files-mismatch.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"state": "available",
"description": "Widely available since JDK 12 (March 2019)"
},
"prev": "io/try-with-resources-effectively-final",
"prev": "io/file-memory-mapping",
"next": "io/deserialization-filters",
"related": [
"io/inputstream-transferto",
Expand Down
2 changes: 1 addition & 1 deletion content/io/try-with-resources-effectively-final.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"description": "Widely available since JDK 9 (Sept 2017)"
},
"prev": "io/path-of",
"next": "io/files-mismatch",
"next": "io/file-memory-mapping",
"related": [
"io/path-of",
"io/reading-files",
Expand Down
2 changes: 1 addition & 1 deletion content/io/writing-files.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"modernLabel": "Java 11+",
"oldApproach": "FileWriter + BufferedWriter",
"modernApproach": "Files.writeString()",
"oldCode": "try (BufferedWriter bw =\n new BufferedWriter(\n new FileWriter(\"out.txt\"))) {\n bw.write(content);\n}",
"oldCode": "try (FileWriter fw =\n new FileWriter(\"out.txt\");\n BufferedWriter bw =\n new BufferedWriter(fw)) {\n bw.write(content);\n}",
"modernCode": "Files.writeString(\n Path.of(\"out.txt\"),\n content\n);",
"summary": "Write a String to a file with one line.",
"explanation": "Files.writeString() writes content to a file with UTF-8 encoding by default. Options can be passed for appending, creating, etc.",
Expand Down
44 changes: 44 additions & 0 deletions content/language/compact-canonical-constructor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": 95,
"slug": "compact-canonical-constructor",
"title": "Compact canonical constructor",
"category": "language",
"difficulty": "intermediate",
"jdkVersion": "16",
"oldLabel": "Java 16",
"modernLabel": "Java 16+",
"oldApproach": "Explicit constructor validation",
"modernApproach": "Compact constructor",
"oldCode": "public record Person(String name,\n List<String> pets) {\n // Full canonical constructor\n public Person(String name,\n List<String> pets) {\n Objects.requireNonNull(name);\n this.name = name;\n this.pets = List.copyOf(pets);\n }\n}",
"modernCode": "public record Person(String name,\n List<String> pets) {\n // Compact constructor\n public Person {\n Objects.requireNonNull(name);\n pets = List.copyOf(pets);\n }\n}",
"summary": "Validate and normalize record fields without repeating parameter lists.",
"explanation": "Records can declare a compact canonical constructor that omits the parameter list and field assignments. The compiler automatically assigns parameters to fields after your validation logic runs. This is ideal for precondition checks, defensive copies, and normalization.",
"whyModernWins": [
{
"icon": "✂️",
"title": "Less repetition",
"desc": "No need to repeat parameter list or assign each field manually."
},
{
"icon": "🛡️",
"title": "Validation",
"desc": "Perfect for null checks, range validation, and defensive copies."
},
{
"icon": "📖",
"title": "Clearer intent",
"desc": "Compact syntax emphasizes validation, not boilerplate."
}
],
"support": {
"state": "available",
"description": "Widely available since JDK 16 (March 2021)"
},
"prev": "language/static-members-in-inner-classes",
"next": null,
"related": [
"language/records-for-data-classes",
"language/flexible-constructor-bodies",
"errors/record-based-errors"
]
}
2 changes: 1 addition & 1 deletion content/language/default-interface-methods.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"description": "Available since JDK 8 (March 2014)."
},
"prev": "tooling/aot-class-preloading",
"next": null,
"next": "language/markdown-javadoc-comments",
"related": [
"language/private-interface-methods",
"language/pattern-matching-instanceof",
Expand Down
44 changes: 44 additions & 0 deletions content/language/markdown-javadoc-comments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": 92,
"slug": "markdown-javadoc-comments",
"title": "Markdown in Javadoc comments",
"category": "language",
"difficulty": "beginner",
"jdkVersion": "23",
"oldLabel": "Java 8",
"modernLabel": "Java 23+",
"oldApproach": "HTML-based Javadoc",
"modernApproach": "Markdown Javadoc",
"oldCode": "/**\n * Returns the {@code User} with\n * the given ID.\n *\n * <p>Example:\n * <pre>{@code\n * var user = findUser(123);\n * }</pre>\n *\n * @param id the user ID\n * @return the user\n */\npublic User findUser(int id) { ... }",
"modernCode": "/// Returns the `User` with\n/// the given ID.\n///\n/// Example:\n/// ```java\n/// var user = findUser(123);\n/// ```\n///\n/// @param id the user ID\n/// @return the user\npublic User findUser(int id) { ... }",
"summary": "Write Javadoc comments in Markdown instead of HTML for better readability.",
"explanation": "Java 23 introduces /// Markdown-style Javadoc comments as an alternative to the traditional /** */ HTML-based format. Markdown syntax is more natural to write and read, with support for code blocks, emphasis, lists, and links. The compiler converts Markdown to HTML for javadoc output.",
"whyModernWins": [
{
"icon": "📖",
"title": "Natural syntax",
"desc": "Use backticks for inline code and ``` for blocks instead of HTML tags."
},
{
"icon": "✍️",
"title": "Easier to write",
"desc": "No need for {@code}, <pre>, <p> tags — just write Markdown."
},
{
"icon": "👁",
"title": "Better in editors",
"desc": "Markdown renders beautifully in modern IDEs and text editors."
}
],
"support": {
"state": "available",
"description": "Available since JDK 23 (Sept 2024)"
},
"prev": "language/default-interface-methods",
"next": "language/static-methods-in-interfaces",
"related": [
"language/text-blocks-for-multiline-strings",
"language/records-for-data-classes",
"language/type-inference-with-var"
]
}
44 changes: 44 additions & 0 deletions content/language/static-members-in-inner-classes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": 94,
"slug": "static-members-in-inner-classes",
"title": "Static members in inner classes",
"category": "language",
"difficulty": "intermediate",
"jdkVersion": "16",
"oldLabel": "Java 8",
"modernLabel": "Java 16+",
"oldApproach": "Must use static nested class",
"modernApproach": "Static members in inner classes",
"oldCode": "class Library {\n // Must be static nested class\n static class Book {\n static int globalBookCount;\n\n Book() {\n globalBookCount++;\n }\n }\n}\n\n// Usage\nvar book = new Library.Book();",
"modernCode": "class Library {\n // Can be inner class with statics\n class Book {\n static int globalBookCount;\n\n Book() {\n Book.globalBookCount++;\n }\n }\n}\n\n// Usage\nvar lib = new Library();\nvar book = lib.new Book();",
"summary": "Define static members in inner classes without requiring static nested classes.",
"explanation": "Before Java 16, only static nested classes could contain static members. Inner (non-static) classes couldn't have statics because they required an enclosing instance. Java 16 relaxes this restriction, allowing static fields, methods, and even nested types in inner classes.",
"whyModernWins": [
{
"icon": "🔓",
"title": "More flexibility",
"desc": "Inner classes can now have static members when needed."
},
{
"icon": "🧩",
"title": "Shared state",
"desc": "Track shared state across instances of an inner class."
},
{
"icon": "📐",
"title": "Design freedom",
"desc": "No need to promote to static nested class just for one static field."
}
],
"support": {
"state": "available",
"description": "Widely available since JDK 16 (March 2021)"
},
"prev": "language/static-methods-in-interfaces",
"next": "language/compact-canonical-constructor",
"related": [
"language/records-for-data-classes",
"language/sealed-classes",
"language/private-interface-methods"
]
}
44 changes: 44 additions & 0 deletions content/language/static-methods-in-interfaces.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": 93,
"slug": "static-methods-in-interfaces",
"title": "Static methods in interfaces",
"category": "language",
"difficulty": "beginner",
"jdkVersion": "8",
"oldLabel": "Java 7",
"modernLabel": "Java 8+",
"oldApproach": "Utility classes",
"modernApproach": "Interface static methods",
"oldCode": "// Separate utility class needed\npublic class ValidatorUtils {\n public static boolean isBlank(\n String s) {\n return s == null ||\n s.trim().isEmpty();\n }\n}\n\n// Usage\nif (ValidatorUtils.isBlank(input)) { ... }",
"modernCode": "public interface Validator {\n boolean validate(String s);\n\n static boolean isBlank(String s) {\n return s == null ||\n s.trim().isEmpty();\n }\n}\n\n// Usage\nif (Validator.isBlank(input)) { ... }",
"summary": "Add static utility methods directly to interfaces instead of separate utility classes.",
"explanation": "Before Java 8, utility methods related to an interface had to live in a separate class (e.g., Collections for Collection). Static methods in interfaces let you keep related utilities together. Common in modern APIs like Comparator.comparing(), Stream.of(), and List.of().",
"whyModernWins": [
{
"icon": "📦",
"title": "Better organization",
"desc": "Keep related utilities with the interface, not in a separate class."
},
{
"icon": "🔍",
"title": "Discoverability",
"desc": "Factory and helper methods are found where you'd expect them."
},
{
"icon": "🧩",
"title": "API cohesion",
"desc": "No need for separate *Utils or *Helper classes."
}
],
"support": {
"state": "available",
"description": "Available since JDK 8 (March 2014)"
},
"prev": "language/markdown-javadoc-comments",
"next": "language/static-members-in-inner-classes",
"related": [
"language/default-interface-methods",
"language/private-interface-methods",
"collections/immutable-list-creation"
]
}