Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Java 8 streams just not intended to be used with Characters and Strings?

I already read this related post. When it comes to String operations, streams seem to attract a huge amount of ceremony. If you want to parse a String as a stream of chars on which you might want to do some operations, you need to convert them to an IntStream first, map to Object, then cast the int to char, eventually casting the char to String and then return it.

And people say imperative style programming has a ceremony overhead. Please correct me if I am completely doing this wrong. My intention is not to mock around but to understand Java streams better because I generally appreciate them.

// Simple method which encrypts all chars in a string
String input = "Hel!lo";

String result = input.chars()                               // Need to convert into an IntStream
        .mapToObj(e -> Character.toUpperCase((char) e))     // Need to map to Object (!) and then cast to char
        .map(CryptoMath::encryptChar)                       // Calling the encryption
        .map(String::valueOf)                               // Need to cast to String again...
        .collect(joining(""));                              // Finally done

System.out.println(result);
like image 764
AdHominem Avatar asked Apr 23 '16 09:04

AdHominem


People also ask

What is the use of streams in Java 8?

Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.

Is Java 8 stream thread safe?

In general no. If the Spliterator used has the CONCURRENT characteristic, then the stream is thread-safe.

Does streams in Java 8 have limited storage?

No storage. Streams don't have storage for values; they carry values from a source (which could be a data structure, a generating function, an I/O channel, etc) through a pipeline of computational steps.


2 Answers

If you can operate on Unicode code points instead of characters, it becomes a bit less cumbersome than operating on char:

String input = "Hel!lo";

String result = input.codePoints()
                     .map( Character::toUpperCase )
                     .collect( StringBuilder::new,
                               StringBuilder::appendCodePoint,
                               StringBuilder::append )
                     .toString();

System.out.println(result);

There's no boxing required, no conversion to string at the point of collection, and you are less likely to be tripped up by surrogate pairs in your input data. One of those nice occasions where it's less painful to implement something that caters for a broader set of inputs.

like image 100
russw_uk Avatar answered Oct 23 '22 05:10

russw_uk


With Eclipse Collections, you can supplement the missing parts in Java standard library. The following will work using CharAdapter, assuming CryptoMath.encryptChar() returns char.

String result = CharAdapter.adapt(input)
        .collectChar(Character::toUpperCase) 
        .collectChar(CryptoMath::encryptChar)
        .makeString("");

Note: I am a committer for Eclipse Collections.

like image 42
itohro Avatar answered Oct 23 '22 03:10

itohro