By Developers, For Developers

Historical errata for Functional Programming in Java

PDF PgPaper PgTypeDescriptionFixed onComments
33ERROR

Hi, the code returning the sum of total number of characters does not work.
Instead of the map function the mapToInt function should be used as in :

System.out.println(“Total number of characters in all names: ” +
friends.stream()
.mapToInt(String::length)
.sum());

Cheers

Mark

2013-06-16
56ERROR

public static int totalAssetValues(final List assets) {
return assets.stream()
.map(asset -> asset.getValue())
.sum();
}

does not compile but using mapToInt does as in :

public static int totalAssetValues(final List assets) {
return assets.stream().mapToInt(Asset::value).sum();
}

2013-06-16
66SUGGEST

Hello,

Thx again for the wonderful work :)

In the filters example when reducing or else to color -> color, a generic identity function like

public final class Functions {
public static Function<T, T> identity() { return t -> t; }
}

could be used.

Using inference(I guess!)m the filter reduction would look like

filter = Arrays.asList(filters).stream()
.reduce(Function<Color, Color>::compose).orElse(Functions::identity);

Cheers

Mark

2013-06-16
97TYPO

“We will first mark this method synthesized…” instead of “We will first mark this method synchronized…”

2013-06-16
106ERROR

Method “Stream.intRange” does not seem to exists. Apparently it is now “IntStream.range”

Cheers

2013-06-16
107ERROR

The method Streams.iterate seems to exist not anymore. But Stream.iterate fulfills the exercise purpose.

cheers

2013-06-16
114ERROR

The method Streams.iterate seems to exist not anymore. But Stream.iterate fulfills the exercise purpose.

2013-06-16
xiiiTYPO

In Chapter 7, Optimizing Recursions, on page 111 we will use lambda expressions to optimize recursions and achieve stellar performance using memoization techniques.

2013-07-10Sorry if I am missing something totally here, I do not see the typo (memoization is the right spelling for this term).
3ERROR

I think there is no sum() on the Stream in the version of the JDK8 build 1.8.0-ea-b96.

Here is the compilation error I get:

DiscountFunctional.java:22: error: cannot find symbol
prices.stream().map((Integer price) -> price * 0.9).sum();
^
symbol: method sum()
location: interface Stream
1 error

I understand that you have used an earlier version that might have had the sum() method. Just wanted to report it.

2013-07-05
53TYPO

I think WatchService was introduced in Java 7. (docs.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html)

The section 3.6 has a reference to Java 6 - “Here we’ll explore the facility already available since Java 6, the WatchService to watch for file change.”

There is also one more sentence in page # 54 - “We see an interplay of a Java 6 feature and the Java 8 features here.”

2013-07-10
44ERROR

In the epub version on pages 44 through 49 of 558, double is used for prices. This code will not always work correctly. Either the data type should be changed to something else (such as a BigDecimal) or an epsilon value is needed for the comparison. I tried to include a link but it was not allowed. Try googling
double currency programming problem
The first stack overflow response wasn’t too bad of an explanation.

2013-11-28
39ERROR

SUMMARY:
cannot find the Collections.joining metod in used in code on page 39, using the latest java8 from oracle:
friends.stream().map(String::toUpperCase).collect(joining(“, ”)));

DETAILS:
nils@lux:/tmp/vsjava8$ tar xzf vsjava8-code.tgz
nils@lux:/tmp/vsjava8$ cd code/collections/fpij/
nils@lux:…/code/collections/fpij$ /usr/lib/jvm/jdk1.8.0/bin/java -version
java version “1.8.0-ea”
Java™ SE Runtime Environment (build 1.8.0-ea-b99)
Java HotSpot™ 64-Bit Server VM (build 25.0-b41, mixed mode)
nils@lux:…/code/collections/fpij$ /usr/lib/jvm/jdk1.8.0/bin/javac *.java
PrintList.java:14: error: cannot find symbol
import static java.util.stream.Collectors.joining;
^
symbol: static joining
location: class
PrintList.java:42: error: cannot find symbol
friends.stream().map(String::toUpperCase).collect(joining(“, ”)));
^
symbol: method joining(String)
location: class PrintList
2 errors
nils@lux:…/code/collections/fpij$

2013-08-19Hi Nils, could you please check to make sure you're using the lambda-8 build of Java 8. The URL for that is given in the book. Thanks. Venkat
296TYPO

The terminal method, send in this example, wraped up the sequence.
wraped should be wrapped

2013-08-02
327TYPO

UseInstance is a functional interface, an ideal candidate for the Java complier to
complier should be compiler

2013-08-02
n/an/aTYPO

Just before section 2.2: “but for now let’s >>>reflection<<< on the wise words of Antoine de Saint-Exupery”

2013-08-30
n/an/aSUGGEST

In 2.4 Reusing Lambda Expressions, consider using .count() instead of .toArray().length()

2013-09-13
110TYPO

“In contract, the ​range​ method,” makes no sense. Propably
“In contrast, the ​range​ method,” was meant.

2013-11-26
13TYPO

Programmers mostly interested in other JVM languages like Scala, Groovy, JRuby, and Closure …

Closure should be ‘Clojure’ instead.

2013-12-15
59TYPO

“filesInCurerentDir” in example “compare/fpij/ListSubDirs.java” should be “filesInCurrentDir”

2014-01-15
19ERROR

the beginning of ch 2 states that Arrays.asList creates an immutable list. It does not. The list is fixed-size, but not fixed-contents. You can call “set” on the list to change the contents at an index.

34SUGGEST

Following code is not a good example:

System.out.println(String.format(“A name starting with %s: %s”,
startingLetter, foundName.orElse(“No name found”)));

The code should use printf instead of println with String.format.

23SUGGEST

I think it is better to use the diamond operator as much as possible. For example:

final List uppercaseNames = new ArrayList();

This should be:

final List uppercaseNames = new ArrayList<>();

382ERROR

This code:
\t
str.chars()
.forEach(ch -> ​System​.out.println(ch));

Won’t work as expected. It will print out the int value for each character. The code to make it print out correctly would be.

str.chars()
.forEach(ch -> ​System​.out.println((char)ch));

This will print the char value as a char.

0TYPO

I presume you folks have noticed that the spine of the printed book says: “Functional Pgrogramming in Java”? Admittedly, I often feel like I am p-grog-ramming when I’m trying to understand Lambdas, but you might want to go with the more conservative spelling for the next print run :-) phillip.hutto@gmail.com

74ERROR

In page 74 Designing Filters

[[
wrapper.apply(input);
The result of that call is the same as doing this:
temp = target.apply(input);
return next.apply(temp);
Without the temporary variable, it would be like this:
return next.apply(target.apply(input));
]]

This is the andThen () method, not compose ()

74ERROR

I expected the filters to be applied in left-to-right order but it’s the other way around.

182SUGGEST

Since we are into removing code noise, this:
System.out.print(String.format(“A name starting with %s: ”, startingLetter));
should be changed into this:
System.out.printf(“A name starting with %s: ”, startingLetter);

and this:
if(foundName != null) {
System.out.println(foundName);
} else {
System.out.println(“No name found”);
}

should be refactorized like this, to stand a fair comparison:

System.out.println(foundName != null ? foundName : “No name found”);

107ERROR

Lazy initialization with Holder class.

This approach has the same problem why double checked locking fails. Potentially a thread can see a half-created HeavyFactory supplier when calling the getHeavy() method.

Making the

private Supplier heavy

field volatile might fix the problem.

68TYPO

Let quickly run these last three calls

should be

Let’s quickly run…

24ERROR

You say in the next to last paragraph that “the map() method collects the result of running the lambda expression and returns the result collection.” It actually returns a Stream

39ERROR

In PrintList.java it is:

.collect(joining(“, ”)));

, but must be:

.collect(Collectors.joining(“, ”));

89ERROR

If I have understood right example

“wrapper = target.compose(next);”

isn’t really same as

“temp = target.apply(input);
return next.apply(temp);”

since compose means that argument is executed first

“default Function<V,R> compose(Function<? super V,? extends T> before)”

Again, if I have understood right everything would be as explained if there would be “andThen” in use instead of “compose”

“default Function<T,V> andThen(Function<? super R,? extends V> after)”

I might mix things, but this is how I interpret use of static method for chaining from java 8 api documentation.

76ERROR

You write “… first it passes through the bright filter, which brightens the shades, then it goes through the dark filter …”.

As far as I read the code:

.reduce( (filter, next) -> filter.compose(next))

then the next filter will be applied first. So it’s actually the dark filter that is applied first and then the bright filter. From the Function javadoc:
/
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies this function to the result.
* …
*/
default Function<V, R> compose(Function<? super V, ? extends T> before)

safriTYPO

A Peek into the default Methods
the implementation in the superclass Vehicle takes precedence here (rule 3)
— Vechicle is not a superclass here..

74ERROR

The order of compose is the other way around.
If you want it this way, you should use:
wrapper = target.andThen(next)
instead of
wrapper = target.compose(next).

71ERROR

In YahooFinance.java the line :
new URL ("" + ticker);
seems to contains an http address (ichart.finance.yahoo.com/table.csv?s=) which is no longer valid. A new valid address would be welcome.
Thanks.

131ERROR

The code for RodCutterMemoized builds correctly on my computer, but at runtime an exception is raised in Memoizer.java at line :
return store.computeIfAbsent(input, key -> function.apply(this, key));

The error message is this :
Exception in thread “main” java.util.ConcurrentModificationException
\tat java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1134)
\tat Java8SubramanianRecur/fpij.Memoizer$1.apply(Memoizer.java:22)
\tat Java8SubramanianRecur/fpij.RodCutterMemoized.lambda$maxProfit$0(RodCutterMemoized.java:27)
\tat Java8SubramanianRecur/fpij.Memoizer$1.lambda$apply$0(Memoizer.java:22)
\tat java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1133)
\tat Java8SubramanianRecur/fpij.Memoizer$1.apply(Memoizer.java:22)
\tat Java8SubramanianRecur/fpij.RodCutterMemoized.lambda$maxProfit$0(RodCutterMemoized.java:27)
\tat Java8SubramanianRecur/fpij.Memoizer$1.lambda$apply$0(Memoizer.java:22)
\tat java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1133)
\tat Java8SubramanianRecur/fpij.Memoizer$1.apply(Memoizer.java:22)
\tat Java8SubramanianRecur/fpij.Memoizer.callMemoized(Memoizer.java:25)
\tat Java8SubramanianRecur/fpij.RodCutterMemoized.maxProfit(RodCutterMemoized.java:32)
\tat Java8SubramanianRecur/fpij.RodCutterMemoized.main(RodCutterMemoized.java:40)

ManySUGGEST

‘concision’ is more concise than ‘conciseness’

133ERROR

As it was reported by somebody else the code for RodCutterMemoized does not work on Java 14 where it throws java.util.ConcurrentModificationException error. To fix this problem one has to replace line

return store.computeIfAbsent(input, key -> function.apply(this, key));

in Memoizer.java with

R value = function.apply(this, input);
store.put(input, value);
return value;

56ERROR

CloseableStream does not exist in the JDK.

Streams might implement the Closeable interface, but there is no CloseableStream class.

131ERROR

Regarding the RodCutterMemoized Concurrency issue mentioned in #84133 and #86676:

For anyone trying the suggested quick fix in #86676: Of course it also requires a check for existing Keys, otherwise there is no memoisation feature. One way of doing it:

In Memoizer.java replace the line:
return store.computeIfAbsent(input, key -> function.apply(this, key));

With those 2 lines:
if (!store.containsKey(input)) store.put(input, function.apply(this, input));
return store.get(input);

Hope it helps.

Categories: