Skip to content

Commit dde8950

Browse files
committed
support yaml, making it easier to contribute
1 parent 3bbca40 commit dde8950

File tree

4 files changed

+79
-63
lines changed

4 files changed

+79
-63
lines changed

content/collections/collectors-teeing.json

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
id: 26
2+
slug: collectors-teeing
3+
title: Collectors.teeing()
4+
category: collections
5+
difficulty: intermediate
6+
jdkVersion: "12"
7+
oldLabel: Java 8
8+
modernLabel: Java 12+
9+
oldApproach: Two Passes
10+
modernApproach: teeing()
11+
oldCode: |
12+
// python
13+
long count = items.stream().count();
14+
double sum = items.stream()
15+
.mapToDouble(Item::price)
16+
.sum();
17+
var result = new Stats(count, sum);
18+
modernCode: |
19+
var result = items.stream().collect(
20+
Collectors.teeing(
21+
Collectors.counting(),
22+
Collectors.summingDouble(Item::price),
23+
Stats::new
24+
)
25+
);
26+
summary: Compute two aggregations in a single stream pass.
27+
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.
28+
whyModernWins:
29+
- icon:
30+
title: Single pass
31+
desc: Process the stream once instead of twice.
32+
- icon: 🧩
33+
title: Composable
34+
desc: Combine any two collectors with a merger function.
35+
- icon: 🔒
36+
title: Immutable result
37+
desc: Merge into a record or value object directly.
38+
support:
39+
state: available
40+
description: Widely available since JDK 12 (March 2019)
41+
prev: collections/sequenced-collections
42+
next: collections/stream-toarray-typed
43+
related:
44+
- collections/copying-collections-immutably
45+
- collections/unmodifiable-collectors
46+
- collections/stream-toarray-typed
47+
docs:
48+
- title: Collectors.teeing()
49+
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)

html-generators/generate.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
///usr/bin/env jbang "$0" "$@" ; exit $?
22
//JAVA 25
33
//DEPS com.fasterxml.jackson.core:jackson-databind:2.18.3
4+
//DEPS com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3
45

56
import module java.base;
67
import com.fasterxml.jackson.core.type.TypeReference;
78
import com.fasterxml.jackson.databind.*;
9+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
810

911
/**
1012
* Generate HTML detail pages from JSON snippet files and slug-template.html.
@@ -14,7 +16,13 @@
1416
static final String CONTENT_DIR = "content";
1517
static final String SITE_DIR = "site";
1618
static final Pattern TOKEN = Pattern.compile("\\{\\{(\\w+)}}");
17-
static final ObjectMapper MAPPER = new ObjectMapper();
19+
static final ObjectMapper JSON_MAPPER = new ObjectMapper();
20+
static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory());
21+
static final Map<String, ObjectMapper> MAPPERS = Map.of(
22+
"json", JSON_MAPPER,
23+
"yaml", YAML_MAPPER,
24+
"yml", YAML_MAPPER
25+
);
1826

1927
static final String CATEGORIES_FILE = "html-generators/categories.properties";
2028
static final SequencedMap<String, String> CATEGORY_DISPLAY = loadCategoryDisplay();
@@ -100,7 +108,7 @@ void main() throws IOException {
100108
// Rebuild data/snippets.json
101109
var snippetsList = allSnippets.values().stream()
102110
.map(s -> {
103-
Map<String, Object> map = MAPPER.convertValue(s.node(), new TypeReference<LinkedHashMap<String, Object>>() {});
111+
Map<String, Object> map = JSON_MAPPER.convertValue(s.node(), new TypeReference<LinkedHashMap<String, Object>>() {});
104112
EXCLUDED_KEYS.forEach(map::remove);
105113
return map;
106114
})
@@ -127,14 +135,16 @@ SequencedMap<String, Snippet> loadAllSnippets() throws IOException {
127135
for (var cat : CATEGORY_DISPLAY.sequencedKeySet()) {
128136
var catDir = Path.of(CONTENT_DIR, cat);
129137
if (!Files.isDirectory(catDir)) continue;
130-
try (var stream = Files.newDirectoryStream(catDir, "*.json")) {
131-
var sorted = new ArrayList<Path>();
132-
stream.forEach(sorted::add);
133-
sorted.sort(Path::compareTo);
134-
for (var path : sorted) {
135-
var snippet = new Snippet(MAPPER.readTree(path.toFile()));
136-
snippets.put(snippet.key(), snippet);
137-
}
138+
for (var ext : MAPPERS.keySet()) {
139+
try (var stream = Files.newDirectoryStream(catDir, "*." + ext)) {
140+
var sorted = new ArrayList<Path>();
141+
stream.forEach(sorted::add);
142+
sorted.sort(Path::compareTo);
143+
for (var path : sorted) {
144+
var snippet = new Snippet(MAPPERS.get(ext).readTree(path.toFile()));
145+
snippets.put(snippet.key(), snippet);
146+
}
147+
}
138148
}
139149
}
140150
return snippets;
@@ -145,7 +155,7 @@ String escape(String text) {
145155
}
146156

147157
String jsonEscape(String text) throws IOException {
148-
var quoted = MAPPER.writeValueAsString(text);
158+
var quoted = JSON_MAPPER.writeValueAsString(text);
149159
var inner = quoted.substring(1, quoted.length() - 1);
150160
var sb = new StringBuilder(inner.length());
151161
for (int i = 0; i < inner.length(); i++) {

html-generators/generate.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""Generate HTML detail pages from JSON snippet files and slug-template.html."""
33

44
import json
5+
import yaml
56
import glob
67
import os
78
import html
@@ -73,10 +74,16 @@ def load_all_snippets():
7374
snippets = {}
7475
json_files = []
7576
for cat in CATEGORY_DISPLAY:
76-
json_files.extend(sorted(glob.glob(f"{CONTENT_DIR}/{cat}/*.json")))
77+
json_files.extend(glob.glob(f"{CONTENT_DIR}/{cat}/*.json"))
78+
json_files.extend(glob.glob(f"{CONTENT_DIR}/{cat}/*.yaml"))
79+
json_files.extend(glob.glob(f"{CONTENT_DIR}/{cat}/*.yml"))
80+
json_files.sort()
7781
for path in json_files:
7882
with open(path) as f:
79-
data = json.load(f)
83+
if path.endswith(".yaml") or path.endswith(".yml"):
84+
data = yaml.safe_load(f)
85+
else:
86+
data = json.load(f)
8087
key = f"{data['category']}/{data['slug']}"
8188
data["_path"] = key
8289
snippets[key] = data

0 commit comments

Comments
 (0)