Java - Lambda
Stream
Create a Stream of String:
jshell> Stream<String> s = Stream.of("a", "b", "c")
s ==> java.util.stream.ReferencePipeline$Head@51565ec2
To collect the stream into a list:
jshell> s.collect(Collectors.toList())
$1 ==> [a, b, c]
Note that Stream can only be "streamed" once
jshell> s.collect(Collectors.toList())
| Exception java.lang.IllegalStateException: stream has already been operated upon or closed
| at AbstractPipeline.evaluate (AbstractPipeline.java:229)
| at ReferencePipeline.collect (ReferencePipeline.java:578)
| at (#11:1)
Lambda
Combining Stream and lambda function we can do a lot of interesting operations.
Change All Strings to Uppercase
jshell> Stream<String> s = Stream.of("a", "b", "c")
s ==> java.util.stream.ReferencePipeline$Head@51565ec2
jshell> s.map(c -> c.toUpperCase()).collect(Collectors.toList())
$1 ==> [A, B, C]
Filter
jshell> int[] a = new int[]{1, -2, 3, -4}
a ==> int[4] { 1, -2, 3, -4 }
jshell> Arrays.stream(a).filter(x -> x > 0).toArray()
$1 ==> int[2] { 1, 3 }
Convert Byte Array To Hex String
1 byte is 8-bit, so each byte can be represented by 2 hex characters, e.g. 127
=> 7F
, 1
=> 01
.
Arrays.stream()
only supports double[]
, int[]
, long[]
or object arrays, so it cannot be used on byte arrays(byte[]
). Here's a workaround:
jshell> byte[] b = new byte[]{1, 127, -3, 42}
b ==> byte[4] { 1, 127, -3, 42 }
jshell> IntStream.range(0, b.length).mapToObj(i -> String.format("%02X", b[i])).collect(Collectors.joining(" "))
$1 ==> "01 7F FD 2A"
One-liner
Print all the lines:
Files.lines(Paths.get("./data.txt")).forEach(System.out::println);
Pattern matching:
Pattern.compile(" ").splitAsStream("a b c").forEach(System.out::println);
Generate random integers
new Random().ints().limit(5).forEach(System.out::println);
Print sorted chars
"hello".chars().sorted().forEach(ch -> System.out.printf("%c ", ch));
Word count
lines.stream()
.flatMap(line -> Stream.of(line.split("\\W+")))
.collect(Collectors.groupingBy(String::toLowerCase, Collectors.summingInt(s -> 1)));
Functional Interfaces
A Functional Interface has one and only one abstract method, and @FunctionalInterface
annotation enforces that.
The following functional interfaces are defined in java.util.function
:
Consumer
: one input, no output(indicating there must be some side effect)BiConsumer
: two inputs, no output
Function
: one input, one outputBiFunction
: two inputs, one output
Supplier
: no input, one outputPredicate
: one input, true/false output
For example, we can define a Consumer
(i.e. a function without output), and reuse it:
jshell> Consumer<Integer> print = i -> System.out.print(i)
print ==> $Lambda$48/0x00000008000dc440@614ddd49
jshell> IntStream.range(0, 5).boxed().forEach(print)
01234
jshell> IntStream.range(5, 10).boxed().forEach(print)
56789
Note that boxed()
is used to convert IntStream
to Stream<Integer>
.