Java Streams and State
blog.frankel.ch
Java Streams and State
1–10 of 33 posts
Re: Java Streams and State
#2Re: Java Streams and State
#3> Notice how state was introduced? It made the code easier to read.
Correct me if I'm wrong, but the only state in that snippet lives in Stream.iterate(), the Fibonacci object is still immutable and next() on it is a pure function. To me this still looks very much like a functional programming approach.
Which just shows that moving business logic into properly named abstractions is good, no matter the programming paradigm.
The real stateful example is the IncrementSupplier and the impure get() method. I personally don't really like it ( Stream.iterate(0, i -> i + 1) is pretty readable to me), but that's probably just personal taste.
Re: Java Streams and State
#4As someone who hasn't written Java since college, I am not familiar with streams. Is this similar in principle to a Python/JS generator function?
Re: Java Streams and State
#5As someone who hasn't written Java since college, I am not familiar with streams. Is this similar in principle to a Python/JS generator function?
``` widgets.stream() .filter(b -> b.getColor() == RED) .mapToInt(b -> b.getWeight()) .sum(); ``` https://docs.oracle.com/javase/8/docs/api/java/util/stream/p...
They aren't specific to Java. In fact they require features such as lambdas that made them less practical until Java 8.
Re: Java Streams and State
#6 Stream.iterate((1,1), ((idx, _)) -> (idx+1, Math.pow(idx+1, 2)));
As an aside, as each term of this particular sequence only depends on the index, not the previous term, the cleanest way would be to just map an index sequence: // Full overflow prevention left as an exercise to the reader
IntStream.rangeClosed(0, Integer.MAX_VALUE).map(n -> Math.pow(n, 2))Re: Java Streams and State
#7That quote shows that the author kinda misses the point here.
type FibPair = (Int, Int)
fibSeed :: FibPair
fibSeed = (0, 1)
fibNext :: FibPair -> FibPair
fibNext (p, v) = (v, v + p)
fibList :: [FibPair]
fibList = iterate fibNext fibSeed
The above code does exactly the same as his Fibonacci example, and it's written in pure Haskell. I'd argue the above is way more readable.I get the following output:
0 1 1 2 3 5 8 13 21 34
With the following main function: main :: IO ()
main = putStrLn . unwords . map (show . fst) . take 10 $ fibList
Which just takes the first element of each generated tuple, maps it to the string representation, and then adds a space between each number.Re: Java Streams and State
#8As someone who hasn't written Java since college, I am not familiar with streams. Is this similar in principle to a Python/JS generator function?
Re: Java Streams and State
#9> Notice how state was introduced? It made the code easier to read. That quote shows that the author kinda misses the point here. type FibPair = (Int, Int) fibSeed :: FibPair fibSeed = (0, 1) fibNext :: FibPair -> FibPair fibNext (p, v) = (v, v + p) fibList :: [FibPair] fibList = iterate fibNext fibSeed The above code does exactly the same as his Fibonacci example, and it's written in pure Haskell. I'd argue the abov…
typealias FibPair = Pair
val fibSeed = FibPair(0, 1)
fun fibNext(pv: FibPair) = pv.let { (p, v) -> FibPair(v, v + p) }
fun fibList(): Sequence = generateSequence(fibSeed, ::fibNext)
fun main() {
fibList().take(10).forEach { (p, _) -> print("$p ") }
}
Honestly I like Kotlin's Sequence abstraction much more than Java streams. It's extremely simple to implement and understand contrary to streams.Re: Java Streams and State
#10This is a very weird statement. It's hidden in exactly the place where it's needed! Where is it hidden from? Where else would you need it? If you're reading the code, it's right there, you don't have to click to definition like you do with Pair::next.
What should I get from reading Pair::next? There's no natural "next" for pairs of numbers. How would I guess that this guy's idea of "next" involves incrementing the first number and then squaring it? To make this equally readable you'd have to rename "Pair" or "next" so that the names were just as informative and easy to read as the lambda itself. So you end up with an unwieldy-but-meaningful name like SquareNumbersIterationState or SquaresSequence.State, which is the classic hallmark of OO programming run amok (aka, the Kingdom of Nouns.)
It's so much nicer to have the lambda inline and see exactly what's happening. One of my favorite things about functional style is that it doesn't force you to noun and name things that are easy to describe but hard to name. Sometimes something can just stand for itself instead of needing an awkward name. I mean, Java isn't the best at this, but this isn't hard to read at all:
pair -> new Pair(pair.index + 1, Math.pow(pair.index + 1, 2)))