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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ site/data/snippets.json
site/index.html

# Generated locale directories (built by html-generators/ for non-English locales)
site/pt-BR/
site/[a-z][a-z]/
site/[a-z][a-z]-[A-Z][A-Z]/

# Platform-specific CDS/AOT intermediate files (generated by build-cds.sh)
html-generators/generate.aot
Expand Down
56 changes: 56 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Contributing

Contributions are welcome! Content is managed as YAML files — never edit generated HTML.

## Adding a new pattern

1. Fork the repo
2. Create a new YAML file in the appropriate `content/<category>/` folder (e.g. `content/language/my-feature.yaml`)
3. Copy [`content/template.json`](content/template.json) as a starting point for all required fields (see the [snippet schema](.github/copilot-instructions.md) for details)
4. Update the `prev`/`next` fields in adjacent pattern files to maintain navigation
5. Run `jbang html-generators/generate.java` to verify your changes build correctly
6. Open a pull request

Please ensure JDK version labels only reference the version where a feature became **final** (non-preview).

## Translating the site

The site supports multiple languages. See [`specs/i18n/i18n-spec.md`](specs/i18n/i18n-spec.md) for the full specification.

### Adding a new locale

1. Add the locale to `html-generators/locales.properties` (e.g. `ja=日本語`)
2. Create `translations/strings/<locale>.yaml` with all UI strings translated (copy `translations/strings/en.yaml` as a starting point)
3. Create content translation files under `translations/content/<locale>/<category>/<slug>.yaml`
4. Run `jbang html-generators/generate.java` and verify the build succeeds
5. Open a pull request

### Translating content files

Translation files contain **only** translatable fields — the generator merges them onto the English base at build time. This prevents translated files from diverging structurally from the English source of truth.

A translation file should contain exactly these fields:

```yaml
title: "Inferencia de tipos con var"
oldApproach: "Tipos explícitos"
modernApproach: "Palabra clave var"
summary: "Usa var para inferencia de tipos..."
explanation: "Desde Java 10, el compilador infiere..."
whyModernWins:
- icon: "⚡"
title: "Menos código repetitivo"
desc: "No es necesario repetir tipos genéricos..."
- icon: "👁"
title: "Mejor legibilidad"
desc: "..."
- icon: "🔒"
title: "Igualmente seguro"
desc: "..."
support:
description: "Ampliamente disponible desde JDK 10 (marzo 2018)"
```

Do **not** include `id`, `slug`, `category`, `difficulty`, `jdkVersion`, `oldCode`, `modernCode`, `prev`, `next`, `related`, or `docs` — these are always taken from the English source.

**Important:** If your text contains colons (`:`), ensure the value is properly quoted in YAML to avoid parse errors. Always validate with `jbang html-generators/generate.java` before submitting.
11 changes: 1 addition & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,7 @@ For development on the generator itself, you can use JBang or Python — see [ht

## Contributing

Contributions are welcome! Content is managed as JSON files — never edit generated HTML.

1. Fork the repo
2. Create a new JSON file in the appropriate `content/<category>/` folder (e.g. `content/language/my-feature.json`)
3. Copy [`content/template.json`](content/template.json) to the new file as a starting point for all required fields (see the [snippet JSON schema](.github/copilot-instructions.md) for details)
4. Update the `prev`/`next` fields in adjacent pattern JSON files to maintain navigation
5. Run `jbang html-generators/generate.java` to verify your changes build correctly
6. Open a pull request

Please ensure JDK version labels only reference the version where a feature became **final** (non-preview).
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details on adding patterns and translating the site.

## Tech stack

Expand Down
50 changes: 0 additions & 50 deletions content/collections/collectors-teeing.json

This file was deleted.

51 changes: 51 additions & 0 deletions content/collections/collectors-teeing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
id: 26
slug: "collectors-teeing"
title: "Collectors.teeing()"
category: "collections"
difficulty: "intermediate"
jdkVersion: "12"
oldLabel: "Java 8"
modernLabel: "Java 12+"
oldApproach: "Two Passes"
modernApproach: "teeing()"
oldCode: |
long count = items.stream().count();
double sum = items.stream()
.mapToDouble(Item::price)
.sum();
var result = new Stats(count, sum);
modernCode: |
var result = items.stream().collect(
Collectors.teeing(
Collectors.counting(),
Collectors.summingDouble(Item::price),
Stats::new
)
);
summary: "Compute two aggregations in a single stream pass."
explanation: "Collectors.teeing() sends each element to two downstream collectors\
\ and merges the results. This avoids streaming the data twice or using a mutable\
\ accumulator."
whyModernWins:
- icon: "⚡"
title: "Single pass"
desc: "Process the stream once instead of twice."
- icon: "🧩"
title: "Composable"
desc: "Combine any two collectors with a merger function."
- icon: "🔒"
title: "Immutable result"
desc: "Merge into a record or value object directly."
support:
state: "available"
description: "Widely available since JDK 12 (March 2019)"
prev: "collections/sequenced-collections"
next: "collections/stream-toarray-typed"
related:
- "collections/copying-collections-immutably"
- "collections/unmodifiable-collectors"
- "collections/stream-toarray-typed"
docs:
- title: "Collectors.teeing()"
href: "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collectors.html#teeing(java.util.stream.Collector,java.util.stream.Collector,java.util.function.BiFunction)"
50 changes: 0 additions & 50 deletions content/collections/copying-collections-immutably.json

This file was deleted.

45 changes: 45 additions & 0 deletions content/collections/copying-collections-immutably.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
id: 22
slug: "copying-collections-immutably"
title: "Copying collections immutably"
category: "collections"
difficulty: "beginner"
jdkVersion: "10"
oldLabel: "Java 8"
modernLabel: "Java 10+"
oldApproach: "Manual Copy + Wrap"
modernApproach: "List.copyOf()"
oldCode: |-
List<String> copy =
Collections.unmodifiableList(
new ArrayList<>(original)
);
modernCode: |-
List<String> copy =
List.copyOf(original);
summary: "Create an immutable copy of any collection in one call."
explanation: "List.copyOf(), Set.copyOf(), and Map.copyOf() create immutable snapshots\
\ of existing collections. If the source is already an immutable collection, no\
\ copy is made."
whyModernWins:
- icon: "⚡"
title: "Smart copy"
desc: "Skips the copy if the source is already immutable."
- icon: "📏"
title: "One call"
desc: "No manual ArrayList construction + wrapping."
- icon: "🛡️"
title: "Defensive copy"
desc: "Changes to the original don't affect the copy."
support:
state: "available"
description: "Widely available since JDK 10 (March 2018)"
prev: "collections/immutable-set-creation"
next: "collections/map-entry-factory"
related:
- "collections/immutable-set-creation"
- "collections/map-entry-factory"
- "collections/immutable-list-creation"
docs:
- title: "List.copyOf()"
href: "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html#copyOf(java.util.Collection)"
54 changes: 0 additions & 54 deletions content/collections/immutable-list-creation.json

This file was deleted.

49 changes: 49 additions & 0 deletions content/collections/immutable-list-creation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
id: 19
slug: "immutable-list-creation"
title: "Immutable list creation"
category: "collections"
difficulty: "beginner"
jdkVersion: "9"
oldLabel: "Java 8"
modernLabel: "Java 9+"
oldApproach: "Verbose Wrapping"
modernApproach: "List.of()"
oldCode: |-
List<String> list =
Collections.unmodifiableList(
new ArrayList<>(
Arrays.asList("a", "b", "c")
)
);
modernCode: |-
List<String> list =
List.of("a", "b", "c");
summary: "Create immutable lists in one clean expression."
explanation: "List.of() creates a truly immutable list — no wrapping, no defensive\
\ copy. It's null-hostile (rejects null elements) and structurally immutable. The\
\ old way required three nested calls."
whyModernWins:
- icon: "📏"
title: "One call"
desc: "Replace three nested calls with a single factory method."
- icon: "🔒"
title: "Truly immutable"
desc: "Not just a wrapper — the list itself is immutable."
- icon: "🛡️"
title: "Null-safe"
desc: "Rejects null elements at creation time, failing fast."
support:
state: "available"
description: "Widely available since JDK 9 (Sept 2017)"
prev: "language/exhaustive-switch"
next: "collections/immutable-map-creation"
related:
- "collections/immutable-map-creation"
- "collections/immutable-set-creation"
- "collections/sequenced-collections"
docs:
- title: "List.of()"
href: "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html#of()"
- title: "Collections Factory Methods (JEP 269)"
href: "https://openjdk.org/jeps/269"
Loading