The key to Java 8's functional features is the new stream library. A Stream in Java is a lazy sequence of values. Each of the collection classes in the Collections framework has a
.stream()
method to get a stream view of its contents. The Arrays class also contains a static method to get a stream view of an array. The following example, which converts each command-line argument to an integer and prints the sum of the positive values only, demonstrates the framework nicely: import java.util.Arrays;
public class SimpleDemo1 {
public static void main(String[] args) {
System.out.println
(Arrays.stream(args).map(s -> Integer.parseInt(s))
.filter(x -> x > 0)
.reduce(0, (x, y) -> x + y));
}
}
Here is an equivalent program in Haskell:
module Main where
import System.Environment
main = do args <- getArgs
putStrLn $ show
$ foldr (+) 0
$ filter (\x -> x > 0)
(map read args :: [Integer])
Here are some noteworthy similarities:
- Both languages use
->
to separate anonymous function arguments from the code. - Java now includes (limited) type inference and an implicit
return
. - Both use lazy evaluation of the streams.
- Both implementations have a similar amount of text:
- Haskell: 30 words, 223 characters
- Java: 31 words, 264 characters
And some noteworthy differences:
- The fundamental paradigms of each language dictate the order in which the computations are written. Note how the Haskell example has the higher-order functions placed in the reverse order of the Java example.
- Lazy evaluation remains pervasive in Haskell, while being confined to this new little corner of Java.
- The syntactic overhead of converting to streams in Java is not too bad, but it is not trivial either. Still, for Java especially, this is an impressive reduction of boilerplate.
I will definitely be including this material in my Data Structures course this semester. I plan to post periodically regarding how I approach the topic and how the students respond.
No comments:
Post a Comment