@@ -110,6 +110,63 @@ new Upper(
110110);
111111```
112112
113+ ### Splitting Text
114+
115+ To split text using Java's standard behavior:
116+
117+ ``` java
118+ Iterable<Text > parts = new Split (" hello,world" , " ," );
119+ // Result: ["hello", "world"]
120+ ```
121+
122+ ### Splitting with Preserved Empty Tokens
123+
124+ Java's ` String.split() ` discards trailing empty tokens.
125+ Use ` SplitPreserveAllTokens ` when you need to preserve ALL tokens,
126+ including empty ones created by adjacent or trailing delimiters:
127+
128+ ``` java
129+ // Standard split loses trailing empty token
130+ " a,b," . split(" ," ) // Returns: ["a", "b"] - trailing empty LOST!
131+
132+ // SplitPreserveAllTokens preserves it
133+ Iterable<Text > parts = new SplitPreserveAllTokens (" a,b," , " ," );
134+ // Result: ["a", "b", ""] - all tokens preserved!
135+ ```
136+
137+ This is essential for parsing CSV/TSV data where empty fields are meaningful:
138+
139+ ``` java
140+ // Parse CSV with empty fields
141+ Iterable<Text > fields = new SplitPreserveAllTokens (
142+ " John,,Smith,,"
143+ " ,"
144+ );
145+ // Result: ["John", "", "Smith", "", ""] - all 5 fields!
146+
147+ // With spaces as delimiter
148+ Iterable<Text > words = new SplitPreserveAllTokens (" hello world " );
149+ // Result: ["", "hello", "", "world", ""]
150+
151+ // Default delimiter is space
152+ Iterable<Text > tokens = new SplitPreserveAllTokens (" a b c" );
153+ // Result: ["a", "b", "c"]
154+
155+ // With limit on number of tokens
156+ Iterable<Text > limited = new SplitPreserveAllTokens (" a,b,c,d" , " ," , 2 );
157+ // Result: ["a", "b"]
158+ ```
159+
160+ ** Key guarantee** : With N delimiters, you always get exactly N+1 tokens.
161+
162+ | Input | Delimiter | ` String.split() ` | ` SplitPreserveAllTokens ` |
163+ | ------- | ----------- | ------------------ | -------------------------- |
164+ | ` "a,b," ` | ` , ` | ` ["a", "b"] ` | ` ["a", "b", ""] ` |
165+ | ` ",," ` | ` , ` | ` [] ` | ` ["", "", ""] ` |
166+ | ` "," ` | ` , ` | ` [] ` | ` ["", ""] ` |
167+
168+ > ** Note** : The delimiter is matched as a literal string, not a regex.
169+
113170## Iterables/Collections/Lists/Sets
114171
115172More about it here:
@@ -254,6 +311,54 @@ final Set<String> sorted = new org.cactoos.set.Sorted<>(
254311);
255312```
256313
314+ ## Maps
315+
316+ To create a simple map:
317+
318+ ``` java
319+ Map<String , Integer > map = new MapOf<> (
320+ new MapEntry<> (" one" , 1 ),
321+ new MapEntry<> (" two" , 2 ),
322+ new MapEntry<> (" three" , 3 )
323+ );
324+ ```
325+
326+ ### Immutable Maps
327+
328+ To create an immutable (read-only) map that prevents any modifications:
329+
330+ ``` java
331+ Map<String , Integer > map = new org.cactoos.map.Immutable<> (
332+ new MapOf<> (
333+ new MapEntry<> (" one" , 1 ),
334+ new MapEntry<> (" two" , 2 )
335+ )
336+ );
337+ map. get(" one" ); // returns 1
338+ map. put(" three" , 3 ); // throws UnsupportedOperationException!
339+ map. clear(); // throws UnsupportedOperationException!
340+ ```
341+
342+ The ` Immutable ` map decorator guarantees that:
343+
344+ - Mutating methods (` put ` , ` remove ` , ` putAll ` , ` clear ` ) are blocked
345+ - Views from ` keySet() ` , ` values() ` , and ` entrySet() ` are immutable
346+ - ` Entry.setValue() ` is blocked on entries from ` entrySet() `
347+
348+ This is useful when you need to pass a map to untrusted code or ensure
349+ a map cannot be accidentally modified:
350+
351+ ``` java
352+ // Safe to pass to any method - cannot be modified
353+ public Map<String , Config > getConfiguration() {
354+ return new Immutable<> (this . config);
355+ }
356+ ```
357+
358+ > ** Note** : This is a decorator, not a copy. If the underlying map is modified
359+ > through another reference, changes will be visible. For a true snapshot,
360+ > copy the data first.
361+
257362## Funcs and Procs
258363
259364This is a traditional ` foreach ` loop:
@@ -331,6 +436,7 @@ final String text = new TextOfDateTime(date).asString();
331436| ` And ` | ` Iterables.all() ` | - | - |
332437| ` Filtered ` | ` Iterables.filter() ` | ? | - |
333438| ` FormattedText ` | - | - | ` String.format() ` |
439+ | ` map.Immutable ` | ` ImmutableMap ` | ` UnmodifiableMap ` | ` unmodifiableMap() ` |
334440| ` IsBlank ` | - | ` StringUtils.isBlank() ` | - |
335441| ` Joined ` | - | - | ` String.join() ` |
336442| ` LengthOf ` | - | - | ` String#length() ` |
@@ -342,6 +448,7 @@ final String text = new TextOfDateTime(date).asString();
342448| ` Reversed ` | - | - | ` StringBuilder#reverse() ` |
343449| ` Rotated ` | - | ` StringUtils.rotate() ` | - |
344450| ` Split ` | - | - | ` String#split() ` |
451+ | ` SplitPreserveAllTokens ` | - | ` StringUtils.splitPreserveAllTokens() ` | - |
345452| ` StickyList ` | ` Lists.newArrayList() ` | ? | ` Arrays.asList() ` |
346453| ` Sub ` | - | - | ` String#substring() ` |
347454| ` SwappedCase ` | - | ` StringUtils.swapCase() ` | - |
@@ -449,26 +556,26 @@ in GitHub precommits.
449556
450557## Contributors
451558
452- * [ @yegor256 ] ( https://github.com/yegor256 ) as Yegor Bugayenko ([ Blog] ( http://www.yegor256.com ) )
453- * [ @g4s8 ] ( https://github.com/g4s8 ) as [ Kirill Che.] ( mailto:g4s8.public@gmail.com )
454- * [ @fabriciofx ] ( https://github.com/fabriciofx ) as Fabrício Cabral
455- * [ @englishman ] ( https://github.com/englishman ) as Andriy Kryvtsun
456- * [ @VsSekorin ] ( https://github.com/VsSekorin ) as Vseslav Sekorin
457- * [ @DronMDF ] ( https://github.com/DronMDF ) as Andrey Valyaev
458- * [ @dusan-rychnovsky ] ( https://github.com/dusan-rychnovsky ) as Dušan Rychnovský ([ Blog] ( http://blog.dusanrychnovsky.cz/ ) )
459- * [ @timmeey ] ( https://github.com/timmeey ) as Tim Hinkes ([ Blog] ( https://blog.timmeey.de ) )
460- * [ @alex-semenyuk ] ( https://github.com/alex-semenyuk ) as Alexey Semenyuk
461- * [ @smallcreep ] ( https://github.com/smallcreep ) as Ilia Rogozhin
462- * [ @memoyil ] ( https://github.com/memoyil ) as Mehmet Yildirim
463- * [ @llorllale ] ( https://github.com/llorllale ) as George Aristy
464- * [ @driver733 ] ( https://github.com/driver733 ) as Mikhail Yakushin
465- * [ @izrik ] ( https://github.com/izrik ) as Richard Sartor
466- * [ @Vatavuk ] ( https://github.com/Vatavuk ) as Vedran Grgo Vatavuk
467- * [ @dgroup ] ( https://github.com/dgroup ) as Yurii Dubinka
468- * [ @iakunin ] ( https://github.com/iakunin ) as Maksim Iakunin
469- * [ @fanifieiev ] ( https://github.com/fanifieiev ) as Fevzi Anifieiev
470- * [ @victornoel ] ( https://github.com/victornoel ) as Victor Noël
471- * [ @paulodamaso ] ( https://github.com/paulodamaso ) as Paulo Lobo
559+ - [ @yegor256 ] ( https://github.com/yegor256 ) as Yegor Bugayenko ([ Blog] ( http://www.yegor256.com ) )
560+ - [ @g4s8 ] ( https://github.com/g4s8 ) as [ Kirill Che.] ( mailto:g4s8.public@gmail.com )
561+ - [ @fabriciofx ] ( https://github.com/fabriciofx ) as Fabrício Cabral
562+ - [ @englishman ] ( https://github.com/englishman ) as Andriy Kryvtsun
563+ - [ @VsSekorin ] ( https://github.com/VsSekorin ) as Vseslav Sekorin
564+ - [ @DronMDF ] ( https://github.com/DronMDF ) as Andrey Valyaev
565+ - [ @dusan-rychnovsky ] ( https://github.com/dusan-rychnovsky ) as Dušan Rychnovský ([ Blog] ( http://blog.dusanrychnovsky.cz/ ) )
566+ - [ @timmeey ] ( https://github.com/timmeey ) as Tim Hinkes ([ Blog] ( https://blog.timmeey.de ) )
567+ - [ @alex-semenyuk ] ( https://github.com/alex-semenyuk ) as Alexey Semenyuk
568+ - [ @smallcreep ] ( https://github.com/smallcreep ) as Ilia Rogozhin
569+ - [ @memoyil ] ( https://github.com/memoyil ) as Mehmet Yildirim
570+ - [ @llorllale ] ( https://github.com/llorllale ) as George Aristy
571+ - [ @driver733 ] ( https://github.com/driver733 ) as Mikhail Yakushin
572+ - [ @izrik ] ( https://github.com/izrik ) as Richard Sartor
573+ - [ @Vatavuk ] ( https://github.com/Vatavuk ) as Vedran Grgo Vatavuk
574+ - [ @dgroup ] ( https://github.com/dgroup ) as Yurii Dubinka
575+ - [ @iakunin ] ( https://github.com/iakunin ) as Maksim Iakunin
576+ - [ @fanifieiev ] ( https://github.com/fanifieiev ) as Fevzi Anifieiev
577+ - [ @victornoel ] ( https://github.com/victornoel ) as Victor Noël
578+ - [ @paulodamaso ] ( https://github.com/paulodamaso ) as Paulo Lobo
472579
473580[ blog ] : http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
474581[ OffsetDateTime ] : https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html
0 commit comments