or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

classfile-builder.mdclassfile.mdindex.mdmemoize.mdpreview.mdresult.mdsignatures.mdstream.mdunmodifiable.md

stream.mddocs/

0

# Enhanced Stream Operations

1

2

Map-specialized stream operations extending Java 8 streams with fluent APIs for key-value pair processing and transformations. This package provides powerful stream operations specifically designed for working with key-value data structures.

3

4

## Capabilities

5

6

### MapStream Interface

7

8

Enhanced stream operations specialized for key-value pairs with full integration with Java 8 Stream API.

9

10

```java { .api }

11

/**

12

* Stream operations specialized for key-value pairs

13

* @param <K> Key type

14

* @param <V> Value type

15

*/

16

public interface MapStream<K, V> extends BaseStream<Map.Entry<K, V>, MapStream<K, V>> {

17

/**

18

* Create a MapStream from a Map

19

* @param map Source map (may be null)

20

* @return MapStream wrapping the map entries

21

*/

22

static <K, V> MapStream<K, V> of(Map<? extends K, ? extends V> map);

23

24

/**

25

* Create a MapStream from a Map, handling null safely

26

* @param map Source map (null becomes empty stream)

27

* @return MapStream wrapping the map entries or empty stream

28

*/

29

static <K, V> MapStream<K, V> ofNullable(Map<? extends K, ? extends V> map);

30

31

/**

32

* Create a MapStream from a collection of entries

33

* @param entries Collection of map entries

34

* @return MapStream wrapping the entries

35

*/

36

static <K, V> MapStream<K, V> of(Collection<? extends Map.Entry<? extends K, ? extends V>> entries);

37

38

/**

39

* Concatenate two MapStreams

40

* @param a First MapStream

41

* @param b Second MapStream

42

* @return Concatenated MapStream

43

*/

44

static <K, V> MapStream<K, V> concat(MapStream<? extends K, ? extends V> a,

45

MapStream<? extends K, ? extends V> b);

46

47

/**

48

* Create an empty MapStream

49

* @return Empty MapStream

50

*/

51

static <K, V> MapStream<K, V> empty();

52

53

/**

54

* Create a MapStream with a single key-value pair

55

* @param key The key

56

* @param value The value

57

* @return MapStream containing one entry

58

*/

59

static <K, V> MapStream<K, V> of(K key, V value);

60

61

/**

62

* Create a MapStream from multiple entries

63

* @param entries Variable number of map entries

64

* @return MapStream containing the entries

65

*/

66

static <K, V> MapStream<K, V> ofEntries(Map.Entry<? extends K, ? extends V>... entries);

67

68

/**

69

* Create a map entry (convenience method)

70

* @param key The key

71

* @param value The value

72

* @return Map entry

73

*/

74

static <K, V> Map.Entry<K, V> entry(K key, V value);

75

}

76

```

77

78

**Usage Example:**

79

80

```java

81

import aQute.bnd.stream.MapStream;

82

import java.util.Map;

83

import java.util.HashMap;

84

import java.util.function.BiPredicate;

85

import java.util.function.BiFunction;

86

import java.util.function.BiConsumer;

87

88

// Create MapStream from existing map

89

Map<String, Integer> scores = new HashMap<>();

90

scores.put("Alice", 95);

91

scores.put("Bob", 87);

92

scores.put("Charlie", 92);

93

94

MapStream<String, Integer> stream = MapStream.of(scores);

95

96

// Create MapStream from entries

97

MapStream<String, String> config = MapStream.ofEntries(

98

MapStream.entry("host", "localhost"),

99

MapStream.entry("port", "8080"),

100

MapStream.entry("timeout", "30000")

101

);

102

103

// Handle null maps safely

104

Map<String, String> nullableMap = getNullableMap();

105

MapStream<String, String> safeStream = MapStream.ofNullable(nullableMap);

106

```

107

108

### Stream Decomposition

109

110

Extract keys, values, or entries as regular Java streams.

111

112

```java { .api }

113

/**

114

* Get the entries as a regular Stream

115

* @return Stream of Map.Entry objects

116

*/

117

Stream<Map.Entry<K, V>> entries();

118

119

/**

120

* Extract keys as a Stream

121

* @return Stream of keys

122

*/

123

Stream<K> keys();

124

125

/**

126

* Extract values as a Stream

127

* @return Stream of values

128

*/

129

Stream<V> values();

130

```

131

132

**Usage Example:**

133

134

```java

135

MapStream<String, Integer> scores = MapStream.of(scoresMap);

136

137

// Process keys

138

List<String> names = scores.keys()

139

.map(String::toUpperCase)

140

.sorted()

141

.collect(Collectors.toList());

142

143

// Process values

144

OptionalInt maxScore = scores.values()

145

.mapToInt(Integer::intValue)

146

.max();

147

148

// Process entries

149

List<String> results = scores.entries()

150

.map(entry -> entry.getKey() + ": " + entry.getValue())

151

.collect(Collectors.toList());

152

```

153

154

### Transformation Operations

155

156

Transform keys, values, or both while maintaining the MapStream structure.

157

158

```java { .api }

159

/**

160

* Transform values while keeping keys unchanged

161

* @param mapper Function to transform values

162

* @return MapStream with transformed values

163

*/

164

<R> MapStream<K, R> mapValue(Function<? super V, ? extends R> mapper);

165

166

/**

167

* Transform keys while keeping values unchanged

168

* @param mapper Function to transform keys

169

* @return MapStream with transformed keys

170

*/

171

<R> MapStream<R, V> mapKey(Function<? super K, ? extends R> mapper);

172

173

/**

174

* Transform both keys and values using a BiFunction

175

* @param mapper Function to transform key-value pairs to new entries

176

* @return MapStream with transformed entries

177

*/

178

<R, S> MapStream<R, S> map(BiFunction<? super K, ? super V, ? extends Map.Entry<? extends R, ? extends S>> mapper);

179

180

/**

181

* FlatMap operation for MapStreams using BiFunction

182

* @param mapper Function to transform key-value pairs to streams of entries

183

* @return Flattened MapStream

184

*/

185

<R, S> MapStream<R, S> flatMap(BiFunction<? super K, ? super V, ? extends MapStream<? extends R, ? extends S>> mapper);

186

```

187

188

**Usage Example:**

189

190

```java

191

MapStream<String, Integer> scores = MapStream.of(scoresMap);

192

193

// Transform values: convert scores to letter grades

194

MapStream<String, String> grades = scores.mapValue(score -> {

195

if (score >= 90) return "A";

196

if (score >= 80) return "B";

197

if (score >= 70) return "C";

198

if (score >= 60) return "D";

199

return "F";

200

});

201

202

// Transform keys: normalize names to lowercase

203

MapStream<String, Integer> normalized = scores.mapKey(String::toLowerCase);

204

205

// Transform both: create descriptive entries

206

MapStream<String, String> descriptions = scores.map((key, value) ->

207

MapStream.entry(key.toUpperCase(), "Score: " + value));

208

209

// FlatMap: expand each student to multiple subjects

210

MapStream<String, Integer> expanded = scores.flatMap((key, value) ->

211

MapStream.ofEntries(

212

MapStream.entry(key + "-Math", value),

213

MapStream.entry(key + "-Science", value + 5)

214

));

215

```

216

217

### Filtering Operations

218

219

Filter MapStream entries based on keys, values, or both.

220

221

```java { .api }

222

/**

223

* Filter entries based on key-value pairs

224

* @param predicate BiPredicate test for key-value pairs

225

* @return Filtered MapStream

226

*/

227

MapStream<K, V> filter(BiPredicate<? super K, ? super V> predicate);

228

229

/**

230

* Filter entries based on keys only

231

* @param predicate Test for keys

232

* @return MapStream with entries having matching keys

233

*/

234

MapStream<K, V> filterKey(Predicate<? super K> predicate);

235

236

/**

237

* Filter entries based on values only

238

* @param predicate Test for values

239

* @return MapStream with entries having matching values

240

*/

241

MapStream<K, V> filterValue(Predicate<? super V> predicate);

242

```

243

244

**Usage Example:**

245

246

```java

247

MapStream<String, Integer> scores = MapStream.of(scoresMap);

248

249

// Filter by key: students whose names start with 'A'

250

MapStream<String, Integer> aStudents = scores.filterKey(name -> name.startsWith("A"));

251

252

// Filter by value: high scores only

253

MapStream<String, Integer> highScores = scores.filterValue(score -> score >= 90);

254

255

// Filter by both: specific criteria for key-value pairs

256

MapStream<String, Integer> filtered = scores.filter((key, value) ->

257

key.length() > 3 && value > 85);

258

259

// Chain filtering operations

260

MapStream<String, Integer> qualified = scores

261

.filterKey(name -> !name.isEmpty())

262

.filterValue(score -> score >= 70)

263

.filter(entry -> !entry.getKey().equals("Test"));

264

```

265

266

### Sorting and Ordering

267

268

Sort MapStream entries by keys, values, or custom comparators.

269

270

```java { .api }

271

/**

272

* Sort entries using natural ordering of entries

273

* @return Sorted MapStream

274

*/

275

MapStream<K, V> sorted();

276

277

/**

278

* Sort entries using a custom comparator

279

* @param comparator Comparator for entries

280

* @return Sorted MapStream

281

*/

282

MapStream<K, V> sorted(Comparator<? super Map.Entry<K, V>> comparator);

283

```

284

285

**Usage Example:**

286

287

```java

288

MapStream<String, Integer> scores = MapStream.of(scoresMap);

289

290

// Sort by key (alphabetically)

291

MapStream<String, Integer> byName = scores.sorted(Map.Entry.comparingByKey());

292

293

// Sort by value (highest scores first)

294

MapStream<String, Integer> byScore = scores.sorted(

295

Map.Entry.<String, Integer>comparingByValue().reversed());

296

297

// Sort by custom criteria

298

MapStream<String, Integer> custom = scores.sorted((e1, e2) -> {

299

// First by score descending, then by name ascending

300

int scoreCompare = Integer.compare(e2.getValue(), e1.getValue());

301

return scoreCompare != 0 ? scoreCompare : e1.getKey().compareTo(e2.getKey());

302

});

303

```

304

305

### Limiting and Skipping

306

307

Limit or skip entries in the MapStream.

308

309

```java { .api }

310

/**

311

* Limit the MapStream to the first n entries

312

* @param maxSize Maximum number of entries

313

* @return Limited MapStream

314

*/

315

MapStream<K, V> limit(long maxSize);

316

317

/**

318

* Skip the first n entries

319

* @param n Number of entries to skip

320

* @return MapStream with skipped entries

321

*/

322

MapStream<K, V> skip(long n);

323

324

/**

325

* Take key-value pairs while predicate is true

326

* @param predicate Test for key-value pairs

327

* @return MapStream of consecutive pairs matching predicate

328

*/

329

MapStream<K, V> takeWhile(BiPredicate<? super K, ? super V> predicate);

330

331

/**

332

* Drop key-value pairs while predicate is true

333

* @param predicate Test for key-value pairs

334

* @return MapStream after dropping consecutive matching pairs

335

*/

336

MapStream<K, V> dropWhile(BiPredicate<? super K, ? super V> predicate);

337

```

338

339

**Usage Example:**

340

341

```java

342

MapStream<String, Integer> scores = MapStream.of(scoresMap);

343

344

// Get top 3 scores

345

MapStream<String, Integer> top3 = scores

346

.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())

347

.limit(3);

348

349

// Skip the highest score and get the next 5

350

MapStream<String, Integer> next5 = scores

351

.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())

352

.skip(1)

353

.limit(5);

354

355

// Take high scores until we find one below 80

356

MapStream<String, Integer> highScoresSequence = scores

357

.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())

358

.takeWhile(entry -> entry.getValue() >= 80);

359

```

360

361

### Reduction and Collection

362

363

Reduce MapStream to single values or collect into various data structures.

364

365

```java { .api }

366

/**

367

* Count the number of entries

368

* @return Number of entries in the stream

369

*/

370

long count();

371

372

/**

373

* Execute an action for each key-value pair

374

* @param consumer Action to perform on each key-value pair

375

*/

376

void forEach(BiConsumer<? super K, ? super V> consumer);

377

378

/**

379

* Test if any key-value pair matches the predicate

380

* @param predicate Test for key-value pairs

381

* @return true if any pair matches

382

*/

383

boolean anyMatch(BiPredicate<? super K, ? super V> predicate);

384

385

/**

386

* Test if all key-value pairs match the predicate

387

* @param predicate Test for key-value pairs

388

* @return true if all pairs match

389

*/

390

boolean allMatch(BiPredicate<? super K, ? super V> predicate);

391

392

/**

393

* Test if no key-value pairs match the predicate

394

* @param predicate Test for key-value pairs

395

* @return true if no pairs match

396

*/

397

boolean noneMatch(BiPredicate<? super K, ? super V> predicate);

398

399

/**

400

* Find the first entry

401

* @return Optional containing first entry, or empty if stream is empty

402

*/

403

Optional<Map.Entry<K, V>> findFirst();

404

405

/**

406

* Find any entry

407

* @return Optional containing any entry, or empty if stream is empty

408

*/

409

Optional<Map.Entry<K, V>> findAny();

410

411

/**

412

* Collect entries using a collector

413

* @param collector Collector to use

414

* @return Collected result

415

*/

416

<R, A> R collect(Collector<? super Map.Entry<K, V>, A, R> collector);

417

```

418

419

### Map Collection

420

421

Collect MapStream back into various Map implementations.

422

423

```java { .api }

424

/**

425

* Collect to a Map

426

* @return Map containing all entries

427

*/

428

static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> toMap();

429

430

/**

431

* Collect to a Map with merge function for duplicate keys

432

* @param mergeFunction Function to resolve duplicate keys

433

* @return Map containing all entries with duplicates resolved

434

*/

435

static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> toMap(BinaryOperator<V> mergeFunction);

436

437

/**

438

* Collect to a specific Map implementation

439

* @param mergeFunction Function to resolve duplicate keys

440

* @param mapSupplier Supplier for the Map implementation

441

* @return Map of specified type containing all entries

442

*/

443

static <K, V, M extends Map<K, V>> Collector<Map.Entry<K, V>, ?, M> toMap(

444

BinaryOperator<V> mergeFunction, Supplier<M> mapSupplier);

445

```

446

447

**Usage Example:**

448

449

```java

450

MapStream<String, Integer> scores = MapStream.of(scoresMap);

451

452

// Count entries

453

long totalStudents = scores.count();

454

455

// Check conditions

456

boolean hasHighScores = scores.anyMatch(entry -> entry.getValue() > 95);

457

boolean allPassed = scores.allMatch(entry -> entry.getValue() >= 60);

458

459

// Find specific entries

460

Optional<Map.Entry<String, Integer>> topScore = scores

461

.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())

462

.findFirst();

463

464

// Collect back to Map

465

Map<String, Integer> filteredScores = scores

466

.filterValue(score -> score >= 80)

467

.collect(MapStream.toMap());

468

469

// Collect to specific Map type

470

LinkedHashMap<String, Integer> orderedScores = scores

471

.sorted(Map.Entry.comparingByKey())

472

.collect(MapStream.toMap(

473

(v1, v2) -> v1, // merge function (shouldn't have duplicates)

474

LinkedHashMap::new));

475

476

// Collect with custom merge function

477

Map<String, Integer> merged = scores

478

.collect(MapStream.toMap(Integer::max)); // Keep maximum value for duplicate keys

479

```

480

481

### Side Effects

482

483

Execute side effects while processing the stream.

484

485

```java { .api }

486

/**

487

* Peek at key-value pairs without consuming them

488

* @param action BiConsumer to perform on each key-value pair

489

* @return MapStream with unchanged entries

490

*/

491

MapStream<K, V> peek(BiConsumer<? super K, ? super V> action);

492

```

493

494

**Usage Example:**

495

496

```java

497

MapStream<String, Integer> scores = MapStream.of(scoresMap);

498

499

// Debug processing pipeline

500

Map<String, String> grades = scores

501

.peek((key, value) -> System.out.println("Processing: " + key + "=" + value))

502

.filterValue(score -> score >= 70)

503

.peek((key, value) -> System.out.println("Passed filter: " + key + "=" + value))

504

.mapValue(score -> score >= 90 ? "A" : score >= 80 ? "B" : "C")

505

.peek((key, grade) -> System.out.println("Final grade: " + key + "=" + grade))

506

.collect(MapStream.toMap());

507

```

508

509

### Distinctness

510

511

Remove duplicate entries based on keys, values, or both.

512

513

```java { .api }

514

/**

515

* Remove duplicate entries (based on key-value pairs)

516

* @return MapStream with distinct entries

517

*/

518

MapStream<K, V> distinct();

519

```

520

521

**Usage Example:**

522

523

```java

524

// Remove exact duplicate entries

525

MapStream<String, Integer> uniqueEntries = scores.distinct();

526

527

// Custom distinctness can be achieved with collect and merge

528

Map<String, Integer> distinctByKey = scores

529

.collect(MapStream.toMap((v1, v2) -> v1)); // Keep first value for each key

530

```

531

532

## Complete Processing Example

533

534

```java

535

import aQute.bnd.stream.MapStream;

536

import java.util.*;

537

import java.util.stream.Collectors;

538

539

public class StudentGradeProcessor {

540

public Map<String, String> processGrades(Map<String, Integer> rawScores) {

541

return MapStream.of(rawScores)

542

// Filter out invalid entries

543

.filterKey(name -> name != null && !name.trim().isEmpty())

544

.filterValue(score -> score >= 0 && score <= 100)

545

546

// Normalize names

547

.mapKey(name -> name.trim().toLowerCase())

548

549

// Remove duplicates (keep highest score)

550

.collect(MapStream.toMap(Integer::max))

551

.let(map -> MapStream.of(map))

552

553

// Convert scores to letter grades

554

.mapValue(score -> {

555

if (score >= 90) return "A";

556

if (score >= 80) return "B";

557

if (score >= 70) return "C";

558

if (score >= 60) return "D";

559

return "F";

560

})

561

562

// Sort by grade (A first), then by name

563

.sorted((e1, e2) -> {

564

int gradeCompare = e1.getValue().compareTo(e2.getValue());

565

return gradeCompare != 0 ? gradeCompare : e1.getKey().compareTo(e2.getKey());

566

})

567

568

// Convert back to regular map

569

.collect(MapStream.toMap());

570

}

571

572

// Helper method for chaining

573

private static <T> T let(T value, Function<T, T> function) {

574

return function.apply(value);

575

}

576

}

577

```

578

579

## Integration with Java Streams

580

581

MapStream seamlessly integrates with regular Java 8 streams:

582

583

```java

584

// Convert to regular stream when needed

585

Stream<Map.Entry<String, Integer>> entryStream = mapStream.entries();

586

Stream<String> keyStream = mapStream.keys();

587

Stream<Integer> valueStream = mapStream.values();

588

589

// Create MapStream from regular streams

590

MapStream<String, Integer> fromStream = MapStream.of(

591

regularStream.collect(Collectors.toMap(keyMapper, valueMapper))

592

);

593

```

594

595

This provides the flexibility to use MapStream where it adds value and fall back to regular streams for operations that don't benefit from the key-value specialization.