I am trying to change some for-each loops to lambda forEach()-methods to discover the possibilities of lambda expressions. The following seems to be possible:
ArrayList<Player> playersOfTeam = new ArrayList<Player>();
for (Player player : players) {
if (player.getTeam().equals(teamName)) {
playersOfTeam.add(player);
}
}
With lambda forEach()
players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});
But the next one doesn't work:
for (Player player : players) {
if (player.getName().contains(name)) {
return player;
}
}
with lambda
players.forEach(player->{if (player.getName().contains(name)) {return player;}});
Is there something wrong in the syntax of the last line or is it impossible to return from forEach() method?
The return there is returning from the lambda expression rather than from the containing method. Instead of forEach you need to filter the stream:
players.stream().filter(player -> player.getName().contains(name))
.findFirst().orElse(null);
Here filter restricts the stream to those items that match the predicate, and findFirst then returns an Optional with the first matching entry.
This looks less efficient than the for-loop approach, but in fact findFirst() can short-circuit - it doesn't generate the entire filtered stream and then extract one element from it, rather it filters only as many elements as it needs to in order to find the first matching one. You could also use findAny() instead of findFirst() if you don't necessarily care about getting the first matching player from the (ordered) stream but simply any matching item. This allows for better efficiency when there's parallelism involved.
I suggest you to first try to understand Java 8 in the whole picture, most importantly in your case it will be streams, lambdas and method references.
You should never convert existing code to Java 8 code on a line-by-line basis, you should extract features and convert those.
What I identified in your first case is the following:
You want to add elements of an input structure to an output list if they match some predicate.
Let's see how we do that, we can do it with the following:
List<Player> playersOfTeam = players.stream()
.filter(player -> player.getTeam().equals(teamName))
.collect(Collectors.toList());
What you do here is:
Turn your input structure into a stream (I am assuming here that it is of type Collection<Player>, now you have a Stream<Player>.
Filter out all unwanted elements with a Predicate<Player>, mapping every player to the boolean true if it is wished to be kept.
Collect the resulting elements in a list, via a Collector, here we can use one of the standard library collectors, which is Collectors.toList().
This also incorporates two other points:
Code against interfaces, so code against List<E> over ArrayList<E>.
Use diamond inference for the type parameter in new ArrayList<>(), you are using Java 8 after all.
Now onto your second point:
You again want to convert something of legacy Java to Java 8 without looking at the bigger picture. This part has already been answered by #IanRoberts, though I think that you need to do players.stream().filter(...)... over what he suggested.
If you want to return a boolean value, then you can use something like this (much faster than filter):
players.stream().anyMatch(player -> player.getName().contains(name));
This what helped me:
List<RepositoryFile> fileList = response.getRepositoryFileList();
RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);
Taken from Java 8 Finding Specific Element in List with Lambda
You can also throw an exception:
Note:
For the sake of readability each step of stream should be listed in new line.
players.stream()
.filter(player -> player.getName().contains(name))
.findFirst()
.orElseThrow(MyCustomRuntimeException::new);
if your logic is loosely "exception driven" such as there is one place in your code that catches all exceptions and decides what to do next. Only use exception driven development when you can avoid littering your code base with multiples try-catch and throwing these exceptions are for very special cases that you expect them and can be handled properly.)
Related
I have the following for loop:
List<Player> players = new ArrayList<>();
for (Team team : teams) {
ArrayList<TeamPlayer> teamPlayers = team.getTeamPlayers();
for (teamPlayer player : teamPlayers) {
players.add(new Player(player.getName, player.getPosition());
}
}
and I'm trying to convert it to a Stream:
List<Player> players = teams.forEach(t -> t.getTeamPlayers()
.forEach(p -> players.add(new Player(p.getName(), p.getPosition())))
);
But I'm getting a compilation error:
variable 'players' might not have been initialized
Why is this happening? Maybe there's an alternative way to create the stream, I was thinking of using flatMap but not sure how to apply it.
First of all, you need to understand that Streams don't act like Loops.
Hence, don't try to mimic a loop. Examine the tools offered by the API. Operation forEach() is there for special cases when you need to perform side-effects, not in order to accumulate elements from the stream into a Collection.
Note: with teams.forEach() you're not actually using a stream, but method Iterable.forEach() which is available with every implementation of Iterable.
To perform reduction on streams, we have several specialized operations like collect, reduce, etc. (for more information refer to the API documentation - Reduction).
collect() operation is meant to perform mutable reduction. You can use to collect the data into a list by providing built-in Collector Collectors.toList() as an argument. And since Java 16 operation toList() was introduced into API, which is implemented on top of the toArray() operation and performs better than namesake collector (therefore it's a preferred option if your JDK version allows you to use it).
I was thinking of using flatMap but not sure how to apply it.
Operation flatMap() is meant to perform one-to-many transformations. It expects a Function which takes a stream element and generates a Stream of the resulting type, elements of the generated stream become a replacement for the initial element.
Note: that general approach to writing streams to use as fewer operations as possible (because one of the main advantages that Functional programming brings to Java is simplicity). For that reason, applying flatMap() when a stream element produces a Collection in a single step is idiomatic, since it's sorter than performing map().flatMap() in two steps.
That's how implementation might look like:
List<Team> teams = List.of();
List<Player> players = teams.stream() // Stream<Team>
.flatMap(team -> team.getTeamPlayers().stream()) // Stream<Player>
.map(player -> new Player(player.getName(), player.getPosition()))
.toList(); // for Java 16+ or collect(Collectors.toList())
This is basically the answer of Alexander Ivanchenko, but with method reference.
final var players = teams.stream()
.map(Team::getTeamPlayers)
.flatMap(Collection::stream)
.map(p -> new Player(p.getName(), p.getPosition()))
.toList();
If your Player class has a factory method like (depending on the relation between Player and TeamPlayer:
public static Player fromTeamPlayer(final TeamPlayer teamPlayer) {
return new Player(teamPlayer.getName(), teamPlayer.getPosition());
}
You could further reduce it to:
final var players = teams.stream()
.map(Team::getTeamPlayers)
.flatMap(Collection::stream)
.map(Player::fromTeamPlayer)
.toList();
Faced to some interesting issue: for example, I have to choose some solutions, depending on whether my List<> is blank or not, but I don't want to use simple if-statement for refactoring reasons (for example, there are three ugly inner if-s). If I had a nullable object, I could use the Optional::ifPresentOrElse solution, but what if the array is not null but just empty? are there any built-in language solutions? I understand that I could write something like ListOptional, create my own ListOptional::isNotEmptyOrElse there, but perhaps there is another solution?
Understand Optional as a wrapper against a possibly null instance providing chainable null-safe methods. Suggested ListOptional doesn't make to me any sense as null and empty lists semantically represent the same - a bunch of nothing.
If you want to use Optional, you must filter the single list in it whether is empty or not and provide an alternative:
List<String> nonEmpty = Optional.of(list)
.filter(l -> !l.isEmpty()) // is the list empty?
.orElseGet(() -> Arrays.asList("Hi", "Bye")); // if so, yield a default one
How is this better than using a ternary operator is questionable. I see no advantage over using this or if-else construct or a wrapper from a 3rd party library:
if (list.isEmpty() {
list = Arrays.asList("Hi", "Bye");
}
A built-in language solution for handling potentially empty collections is Stream API as declarative calls of chained methods, that are not executed on Stream from an empty collection. You can understand Stream as a wrapper against a possibly empty collection with the goal of processing each element. The same goes to the Optional with a difference a single instance is handled (regardless of whether it is a collection or not).
List<String> list = Collections.emptyList(); // empty list
List<String> updated = list.stream()
.filter(str -> str.startsWith("A") // won't happen
.map(String::toLowerCase) // won't happen
.collect(Collectors.toList()); // yields empty list
I have a List defined as follows:
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
How can I increment each element of the List by one (i.e. end up with a List [2,3]) using Java 8's Stream API without creating new List?
When you create a Stream from the List, you are not allowed to modify the source List from the Stream as specified in the “Non-interference” section of the package documentation. Not obeying this constraint can result in a ConcurrentModificationException or, even worse, a corrupted data structure without getting an exception.
The only solution to directly manipulate the list using a Java Stream, is to create a Stream not iterating over the list itself, i.e. a stream iterating over the indices like
IntStream.range(0, list1.size()).forEach(ix -> list1.set(ix, list1.get(ix)+1));
like in Eran’s answer
But it’s not necessary to use a Stream here. The goal can be achieved as simple as
list1.replaceAll(i -> i + 1);
This is a new List method introduced in Java 8, also allowing to smoothly use a lambda expression. Besides that, there are also the probably well-known Iterable.forEach, the nice Collection.removeIf, and the in-place List.sort method, to name other new Collection operations not involving the Stream API. Also, the Map interface got several new methods worth knowing.
See also “New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in Java SE 8” from the official documentation.
Holger's answer is just about perfect. However, if you're concerned with integer overflow, then you can use another utility method that was released in Java 8: Math#incrementExact. This will throw an ArithmeticException if the result overflows an int. A method reference can be used for this as well, as seen below:
list1.replaceAll(Math::incrementExact);
You can iterate over the indices via an IntStream combined with forEach:
IntStream.range(0,list1.size()).forEach(i->list1.set(i,list1.get(i)+1));
However, this is not much different than a normal for loop, and probably less readable.
reassign the result to list1:
list1 = list1.stream().map(i -> i+1).collect(Collectors.toList());
public static Function<Map<String, LinkedList<Long>>, Map<String, LinkedList<Long>>> applyDiscount = (
objectOfMAp) -> {
objectOfMAp.values().forEach(listfLong -> {
LongStream.range(0, ((LinkedList<Long>) listfLong).size()).forEach(index -> {
Integer position = (int) index;
Double l = listfLong.get(position) - (10.0 / 100 * listfLong.get(position));
listfLong.set(position, l.longValue());
});
});
return objectOfMAp;
};
I want to use Optional for a method which returns a List
Lets say the function is
public Output getListOfSomething() {
// In some cases there is nothing to return and hence it makes sense to have return
// type as Optional here
}
Hence the function looks like :
public Optional<List<String>> getListOfSomething() {
// return something only when there is some valid list
}
Now I want to do something if the list is present so something like :
Optional<List<String>> listOfSomething = getListOfSomething();
int size = 0;
listOfSomething.ifPresent(size = listOfSomething.get().size());
I am new to Optional and have gone through the articles about Optional and it seems like this should work however am getting syntax error in my IDE :
method ifPresent is not applicable for the arguments (void).
I wanted to get some help from developers who might be more fluent with lamdas in java 8.
It's important to think about the Semantics here.
Your method could return a List, or "no list".
If it returns a List, it could return an Empty list.
You should ask, "is there a semantic reason to distinguish between an Empty List, and No List?" Sometimes there is a good design reason to make the difference, but it is rare. Think long and hard before deciding that Empty and Null are different in your case. Part of the reason to avoid No List, is that it reduces "special cases" that the client code has to consider. For example, if they have to do something for every item returned, but you could also return null, they have to do a special check for null before going into a for each loop. A for each does nothing if the list is empty.
If a "No List" is distinct from an "Empty List" in your problem domain, then it is sometimes useful to return wrapper class that helps client code distinguish between those conditions, and handle them appropriately. Optional is one such generic class, but your domain may call for something more specific (even if it mimics the functionality of Optional, it might have better semantic definition).
The true functional-programming way is the following:
size = listOfSomething.map(List::size).orElse(0);
But it would be much better to return an empty List instead of Optional.
ifPresent requires a Consumer interface to work. You could do the following:
Optional<List<String>> listOfSomething = getListOfSomething();
Integer[] size = {0};
listOfSomething.ifPresent(list -> size[0]=list.size())
But as stated by Tagir Valeev it would be better to do:
size = listOfSomething.map(List::size).orElse(0);
And it would also be better to return an empty List or even a Stream maybe.
I'm working on getting my head around some of the Java 8 Stream features. I'm tolerably familiar with FP, having written some Lisp thirty years ago, and I think I might be trying to do something this new facility isn't really targeted at. Anyway, if the question is stupid, I'm happy to learn the error of my ways.
I'll give a specific problem, though it's really a general concept I'm trying to resolve.
Suppose I want to get a Stream from every third element of a Stream. In regular FP I would (approximately) create a recursive function that operates by concatenating the first element of the list with the (call-thyself) of the remainder of the list after dropping two elements. Easy enough. But to do this in a stream, I feel like I want one of two tools:
1) a means of having an operation extract multiple items from the stream for processing (then I'd just grab three, use the first, and dump the rest)
2) a means of making a Supplier that takes an item and a Stream and creates a Stream. Then it feels like I could create a downstream stream out of the first item and the shortened stream, though it's still unclear to me if this would do the necessary recursive magic to actually work.
BEGIN EDIT
So, there's some interesting and useful feedback; thanks everyone. In particular, the comments have helped me clarify what my head is trying to get around a bit better.
First, one can--conceptually, at least--having / needing knowledge of order in a sequence should not prevent one from permitting fully parallelizable operations. An example sprang to mind, and that's the convolution operations that graphics folks are inclined to do. Imagine blurring an image. Each pixel is modified by virtue of pixels near to it, but those pixels are only read, not modified, in themselves.
It's my understanding (very shaky at this stage, for sure!) that the streams mechanism is the primary entry point to the wonderful world of VM managed parallelism, and that iterators are still what they always were (yes? no?) If that's correct, then using the iterator to solve the problem domain that I'm waffling around doesn't seem great.
So, at this point, at least, the suggestion to create a chunking spliterator seems the most promising, but boy, does the code that supports that example seem like hard work! I think I'd rather do it with a ForkJoin mechanism, despite it being "old hat" now :)
Anyway, still interested in any more insights folks wish to offer.
END EDIT
Any thoughts? Am I trying to use these Streams to do something they're not intended for, or am I missing something obvious?
Cheers,
Toby.
One of the things to keep in mind is that Stream was primarily designed to be a way of taking advantage of parallel processing. An implication of this is that they have a number of conditions associated with them that are aimed at giving the VM a lot of freedom to process the elements in any convenient order. An example of this is insisting that reduction functions are associative. Another is that local variables manipulated are final. These types of conditions mean the stream items can be evaluated and collected in any order.
A natural consequence of this is that the best use cases for Stream involve no dependencies between the values of the stream. Things such as mapping a stream of integers to their cumulative values are trivial in languages like LISP but a pretty unnatural fit for Java streams (see this question).
There are clever ways of getting around some of these restrictions by using sequential to force the Stream to not be parallel but my experience has been that these are more trouble than they are worth. If your problem involves an essentially sequential series of items in which state is required to process the values then I recommend using traditional collections and iteration. The code will end up being clearer and will perform no worse given the stream cannot be parallelised anyway.
Having said all that, if you really want to do this then the most straightforward way is to have a collector that stores every third item then sends them out as a stream again:
class EveryThird {
private final List<Integer> list = new ArrayList<>();
private int count = 0;
public void accept(Integer i) {
if (count++ % 3 == 0)
list.add(i);
}
public EveryThird combine(EveryThird other) {
list.addAll(other.list);
count += other.count;
return this;
}
public Stream<Integer> stream() {
return list.stream();
}
}
This can then be used like:
IntStream.range(0, 10000)
.collect(EveryThird::new, EveryThird::accept, EveryThird::combine)
.stream()
But that's not really what collectors are designed for and this is pretty inefficient as it's unnecessarily collecting the stream. As stated above my recommendation is to use traditional iteration for this sort of situation.
My StreamEx library enhances standard Stream API. In particular it adds the headTail method which allows recursive definition of custom operations. It takes a function which receives stream head (first element) and tail (stream of the rest elements) and should return the resulting stream which will be used instead of the original one. For example, you can define every3 operation as follows:
public static <T> StreamEx<T> every3(StreamEx<T> input) {
return input.headTail(
(first, tail1) -> tail1.<T>headTail(
(second, tail2) -> tail2.headTail(
(third, tail3) -> every3(tail3))).prepend(first));
}
Here prepend is also used which just prepends the given element to the stream (this operation is just a best friend of headTail.
In general using headTail you can define almost any intermediate operation you want, including existing ones and new ones. You may find some samples here.
Note that I implemented some mechanism which optimizes tails in such recursive operation definition, so properly defined operation will not eat the whole stack when processing the long stream.
Java's streams are nothing like FP's (lazy) sequences. If you are familiar with Clojure, the difference is exactly like the difference between lazy seq and reducer. Whereas the lazy seq packages all processing with each element individually, and thus allows getting individually processed elements, a reducer collapses the complete sequence in a single atomic operation.
Specifically for the example you have described, consider relying on a stream partitioning transformation, as described in detail here. You would then easily do
partition(originalStream, 3).map(xs -> xs.get(0));
resulting in a stream having every third element of the original.
This would maintain efficiency, laziness, and parallelizability.
You can use (or peek at the source) of BatchingSpliterator
Then given aStream you can create a stream that consists of lists with size=3 (except maybe for the last one) and use the first element of that list
Stream<T> aStream = ...;
Stream<List<T>> batchedStream =
new BatchingSpliterator.Builder().wrap(aStream).batchSize(3).stream();
batchedStream.map(l -> l.get(0) ). ...
You can also "go parallel":
batchedStream.parallel().map(l -> l.get(0) ). ....