There are two completely different things you should ask here:
a) how do I place multiple lines of code in stream.forEach()?
b) what should I do to count the number of lines in a Stream?
The question b) is answered already by other posters; on the other hand, the general question a) has a quite different answer:
use a (possibly multi-line) lambda expression or pass a reference to multi-line method.
In this particular case, you'd either declare i a field or use a counter/wrapper object instead of i.
For example, if you want to have multiple lines in forEach() explicitly, you can use
class Counter { // wrapper class
private int count;
public int getCount() { return count; }
public void increaseCount() { count++; }
}
and then
Counter counter = new Counter();
lines.stream().forEach( e -> {
System.out.println(e);
counter.increaseCounter(); // or i++; if you decided i is worth being a field
} );
Another way to do it, this time hiding those multiple lines in a method:
class Counter { // wrapper class
private int count;
public int getCount() { return count; }
public void increaseCount( Object o ) {
System.out.println(o);
count++;
}
}
and then
Counter counter = new Counter();
lines.stream().forEach( counter::increaseCount );
or even
Counter counter = new Counter();
lines.stream().forEach( e -> counter.increaseCount(e) );
The second syntax comes in handy if you need a consumer having more than one parameter; the first syntax is still the shortest and simplest though.
Answer from user719662 on Stack OverflowThere are two completely different things you should ask here:
a) how do I place multiple lines of code in stream.forEach()?
b) what should I do to count the number of lines in a Stream?
The question b) is answered already by other posters; on the other hand, the general question a) has a quite different answer:
use a (possibly multi-line) lambda expression or pass a reference to multi-line method.
In this particular case, you'd either declare i a field or use a counter/wrapper object instead of i.
For example, if you want to have multiple lines in forEach() explicitly, you can use
class Counter { // wrapper class
private int count;
public int getCount() { return count; }
public void increaseCount() { count++; }
}
and then
Counter counter = new Counter();
lines.stream().forEach( e -> {
System.out.println(e);
counter.increaseCounter(); // or i++; if you decided i is worth being a field
} );
Another way to do it, this time hiding those multiple lines in a method:
class Counter { // wrapper class
private int count;
public int getCount() { return count; }
public void increaseCount( Object o ) {
System.out.println(o);
count++;
}
}
and then
Counter counter = new Counter();
lines.stream().forEach( counter::increaseCount );
or even
Counter counter = new Counter();
lines.stream().forEach( e -> counter.increaseCount(e) );
The second syntax comes in handy if you need a consumer having more than one parameter; the first syntax is still the shortest and simplest though.
The forEach method takes an instance of any class that implements Consumer. So here is an example of using a custom Consumer implementation that keeps up with the count. Later you can call getCount() on the Consumer implementation to get the count.
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
List<String> lines = new ArrayList<String>();
lines.add("line 1");
lines.add("line 2");
MyConsumer countingConsumer = new MyConsumer();
lines.stream().forEach(countingConsumer);
System.out.println("Count: " + countingConsumer.getCount());
}
private static class MyConsumer implements Consumer<String> {
private int count;
@Override
public void accept(String t) {
System.out.println(t);
count++;
}
public int getCount() {
return count;
}
}
}
WARNING
As mentioned in comments, Using peek() for production code is considered bad practice
The reasson is that "According to its JavaDocs, the intermediate Stream operation java.util.Stream.peek() “exists mainly to support debugging” purposes."
As a consequence, this proposed solution SHOULD NOT be used.
Forgot to relate to the first code snippet. I wouldn't use forEach at all. Since you are collecting the elements of the Stream into a List, it would make more sense to end the Stream processing with collect. Then you would need peek in order to set the ID.
List<Entry> updatedEntries =
entryList.stream()
.peek(e -> e.setTempId(tempId))
.collect (Collectors.toList());
For the second snippet, forEach can execute multiple expressions, just like any lambda expression can :
entryList.forEach(entry -> {
if(entry.getA() == null){
printA();
}
if(entry.getB() == null){
printB();
}
if(entry.getC() == null){
printC();
}
});
However (looking at your commented attempt), you can't use filter in this scenario, since you will only process some of the entries (for example, the entries for which entry.getA() == null) if you do.
List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
items.add("D");
items.add("E");
//lambda
//Output : A,B,C,D,E
items.forEach(item->System.out.println(item));
//Output : C
items.forEach(item->{
System.out.println(item);
System.out.println(item.toLowerCase());
}
});
Just add a new line before the 2nd IntStream.
IntStream.iterate(1, i -> i + 1).limit(5).forEach(i -> {
System.out.println();
IntStream.iterate(1, j -> j + 1).limit(5).forEach(System.out::print);
});
NB: I have also modified the last foreach for my preference.
To add the line after every forEach loop need to add println after the second forEach such as below.
`
public static void main(String[] args) {
// TODO Auto-generated method stub
Runnable r2 = () -> {
IntStream.iterate(1, i -> i + 1).limit(5)
.forEach(i -> {
IntStream.iterate(1, j -> j + 1).limit(5).forEach(j -> {
System.out.print(j);
});
System.out.println();
});
};
new Thread(r2).start();
}
I understand the forEach method in this case expects a Consumer Functional Interface` which has below signature
forEach() expects indeed a Consumer but to process a Consumer you don't need necessarily a Consumer. What you need is a method that respects the input/output of the Consumer functional interface, that is Entry<Integer,String> input / void output.
So you could just invoke a method that has as parameter the Entry :
testMap.entrySet().forEach(k-> useEntry(k)));
or
testMap.entrySet().forEach(this::useEntry));
with useEntry() such as :
private void useEntry(Map.Entry<Integer,String> e)){
System.out.println("Key ="+e.getKey()+" Value = "+e.getValue());
System.out.println("Some more processing ....");
}
Declaring a Consumer<Map.Entry<Integer,String>> that you pass to forEach() such as :
Consumer<Map.Entry<Integer,String>> consumer = this::useEntry;
//...used then :
testMap.entrySet().forEach(consumer);
makes sense only if the consumer in your forEach() is designed to be variabilized in a some way (computed/passed by the client or anyway).
If you are not in this case and that you use a Consumer, you finally made things more abstract and complicated than it is effectively required.
What about
public void processMap(Map.Entry K){
System.out.println("Key ="+K.getKey()+" Value = "+K.getValue());
System.out.println("Some more processing ....");
}
and then use it like:
testMap.entrySet().forEach((K)-> processMap(K));
Yes, you can use a lambda expression :
someIntStream.forEach(result -> System.out.print(result + " "));
or, if you wish to still use a method reference, add a mapToObj step :
someIntStream.mapToObj(result -> result + " ").forEach(System.out::print);
Many ways that avoid collection before output:
Lambda with overhead of two method calls, but avoiding object creation/reallocation on each entry:
intStream.forEach(s -> {
System.out.print(s);
System.out.print(" ");
});
Lambda incurring StringBuilder overhead:
intStream.forEach(s -> System.out.print(s + " "));
Using string format (likely similar overhead to the StringBuilder):
intStream.forEach(s -> System.out.printf("%d ", s));
It's fairly deeply nested but it doesn't seem exceptionally difficult.
The first observation is that if a for-loop translates into a stream, nested for-loops can be "flattened" into a single stream using flatMap. This operation takes a single element and returns an arbitrary number elements in a stream. I looked up and found that StandardServer.findServices() returns an array of Service so we turn this into a stream using Arrays.stream(). (I make similar assumptions for Engine.findChildren() and Host.findChildren().
Next, the logic within each loop does an instanceof check and a cast. This can be modeled using streams as a filter operation to do the instanceof followed by a map operation that simply casts and returns the same reference. This is actually a no-op but it lets the static typing system convert a Stream<Container> to a Stream<Host> for example.
Applying these transformations to the nested loops, we get the following:
public List<ContextInfo> list() {
final List<ContextInfo> list = new ArrayList<ContextInfo>();
final StandardServer server = getServer();
Arrays.stream(server.findServices())
.filter(service -> service.getContainer() instanceof Engine)
.map(service -> (Engine)service.getContainer())
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.filter(possibleHost -> possibleHost instanceof Host)
.map(possibleHost -> (Host)possibleHost)
.flatMap(host -> Arrays.stream(host.findChildren()))
.filter(possibleContext -> possibleContext instanceof Context)
.map(possibleContext -> (Context)possibleContext)
.forEach(context -> {
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
list.add(info);
});
return list;
}
But wait, there's more.
The final forEach operation is a slightly more complicated map operation that converts a Context into a ContextInfo. Furthermore, these are just collected into a List so we can use collectors to do this instead of creating and empty list up front and then populating it. Applying these refactorings results in the following:
public List<ContextInfo> list() {
final StandardServer server = getServer();
return Arrays.stream(server.findServices())
.filter(service -> service.getContainer() instanceof Engine)
.map(service -> (Engine)service.getContainer())
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.filter(possibleHost -> possibleHost instanceof Host)
.map(possibleHost -> (Host)possibleHost)
.flatMap(host -> Arrays.stream(host.findChildren()))
.filter(possibleContext -> possibleContext instanceof Context)
.map(possibleContext -> (Context)possibleContext)
.map(context -> {
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
return info;
})
.collect(Collectors.toList());
}
I usually try to avoid multi-line lambdas (such as in the final map operation) so I'd refactor it into a little helper method that takes a Context and returns a ContextInfo. This doesn't shorten the code at all, but I think it does make it clearer.
UPDATE
But wait, there's still more.
Let's extract the call to service.getContainer() into its own pipeline element:
return Arrays.stream(server.findServices())
.map(service -> service.getContainer())
.filter(container -> container instanceof Engine)
.map(container -> (Engine)container)
.flatMap(engine -> Arrays.stream(engine.findChildren()))
// ...
This exposes the repetition of filtering on instanceof followed by a mapping with a cast. This is done three times in total. It seems likely that other code is going to need to do similar things, so it would be nice to extract this bit of logic into a helper method. The problem is that filter can change the number of elements in the stream (dropping ones that don't match) but it can't change their types. And map can change the types of elements, but it can't change their number. Can something change both the number and types? Yes, it's our old friend flatMap again! So our helper method needs to take an element and return a stream of elements of a different type. That return stream will contain a single casted element (if it matches) or it will be empty (if it doesn't match). The helper function would look like this:
<T,U> Stream<U> toType(T t, Class<U> clazz) {
if (clazz.isInstance(t)) {
return Stream.of(clazz.cast(t));
} else {
return Stream.empty();
}
}
(This is loosely based on C#'s OfType construct mentioned in some of the comments.)
While we're at it, let's extract a method to create a ContextInfo:
ContextInfo makeContextInfo(Context context) {
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
return info;
}
After these extractions, the pipeline looks like this:
return Arrays.stream(server.findServices())
.map(service -> service.getContainer())
.flatMap(container -> toType(container, Engine.class))
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.flatMap(possibleHost -> toType(possibleHost, Host.class))
.flatMap(host -> Arrays.stream(host.findChildren()))
.flatMap(possibleContext -> toType(possibleContext, Context.class))
.map(this::makeContextInfo)
.collect(Collectors.toList());
Nicer, I think, and we've removed the dreaded multi-line statement lambda.
UPDATE: BONUS CHALLENGE
Once again, flatMap is your friend. Take the tail of the stream and migrate it into the last flatMap before the tail. That way the host variable is still in scope, and you can pass it to a makeContextInfo helper method that's been modified to take host as well.
return Arrays.stream(server.findServices())
.map(service -> service.getContainer())
.flatMap(container -> toType(container, Engine.class))
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.flatMap(possibleHost -> toType(possibleHost, Host.class))
.flatMap(host -> Arrays.stream(host.findChildren())
.flatMap(possibleContext -> toType(possibleContext, Context.class))
.map(ctx -> makeContextInfo(ctx, host)))
.collect(Collectors.toList());
This would be my version of your code using JDK 8 streams, method references, and lambda expressions:
server.findServices()
.stream()
.map(Service::getContainer)
.filter(Engine.class::isInstance)
.map(Engine.class::cast)
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.filter(Host.class::isInstance)
.map(Host.class::cast)
.flatMap(host -> Arrays.stream(host.findChildren()))
.filter(Context.class::isInstance)
.map(Context.class::cast)
.map(context -> {
ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
return info;
})
.collect(Collectors.toList());
In this approach, I replace your if-statements for filter predicates. Take into account that an instanceof check can be replaced with a Predicate<T>
Predicate<Object> isEngine = someObject -> someObject instanceof Engine;
which can also be expressed as
Predicate<Object> isEngine = Engine.class::isInstance
Similarly, your casts can be replaced by Function<T,R>.
Function<Object,Engine> castToEngine = someObject -> (Engine) someObject;
Which is pretty much the same as
Function<Object,Engine> castToEngine = Engine.class::cast;
And adding items manually to a list in the for loop can be replaced with a collector. In production code, the lambda that transforms a Context into a ContextInfo can (and should) be extracted into a separate method, and used as a method reference.
The lambda parameter i takes the value of the items in the collection, not the indexes. You are subtracting 1 because the values happen to be one greater than their index.
If you tried with
List<Integer> ints = Stream.of(10,20,40,30,50).collect(Collectors.toList());
ints.forEach((i)-> System.out.print(ints.get(i-1)+ " "));
You would find the code does not work so well.
You should be able to simply do (not needing to do a get call)
ints.forEach((i)-> System.out.print(i + " "));
Your lambda and your proposed for loop are not equivalent.
ints.forEach((i)-> System.out.print(ints.get(i-1)))
Would be equivalent to
for(Integer i:ints)
System.out.print(ints.get(i-1));
Note the preservation of the minus 1.
In response to the comment:
Lambdas are not loops, they are functions (effectively anyway). In your first example the forEach method is what provides the looping functionality. The argument lambda is what it should do on each iteration. This is equivalent to the body of your for loop
In the example in the comment, max is the function that provides the loop like behavior. It will iterate (do a loop) of the items to find the maximum value). The lambda you provide i -> i would be an identity function. It takes one parameter and returns that object unmodified.
Suppose you had a more complex object and you wanted to compare them on a particular member such as GetHighScore(). Then you could use i -> i.GetHighScore() to get the object with the highest score.
List indexes in Java are 0-based.
Therefore:
ints.get(0) == 1;
ints.get(1) == 2;
ints.get(2) == 3;
//etc...
You're calling ints.get(i-1) for each "i" where "i" is equal to the value of each element in the list "ints".
If you were to call ints.get(i) you'd be fetching elements with indices equal to 1,2,3,4 and 5 and 5 wouldn't be a valid index into a list with 5 elements.
This code:
ints.forEach((i)-> System.out.print(ints.get(i-1)+ " "));
is equivalent to:
for(int i : ints ) {
System.out.print(ints.get(i-1) + " ");
}
Your examples aren't equivalent.
The lambda syntax allows two kinds of definitions for the body:
- a single, value-returning, expression, eg:
x -> x*2 - multiple statements, enclosed in curly braces, eg:
x -> { x *= 2; return x; }
A third special case is the one that allows you to avoid using curly braces, when invoking a void returning method, eg: x -> System.out.println(x).
Use this:
map.forEach(
(k,v) -> {
System.out.println(k);
v.forEach(t->System.out.print(t.getDescription()))
}
);
The better practice is to use for-each. Besides violating the Keep It Simple, Stupid principle, the new-fangled forEach() has at least the following deficiencies:
- Can't use non-final variables. So, code like the following can't be turned into a forEach lambda:
Object prev = null; for(Object curr : list) { if( prev != null ) foo(prev, curr); prev = curr; }
Can't handle checked exceptions. Lambdas aren't actually forbidden from throwing checked exceptions, but common functional interfaces like
Consumerdon't declare any. Therefore, any code that throws checked exceptions must wrap them intry-catchorThrowables.propagate(). But even if you do that, it's not always clear what happens to the thrown exception. It could get swallowed somewhere in the guts offorEach()Limited flow-control. A
returnin a lambda equals acontinuein a for-each, but there is no equivalent to abreak. It's also difficult to do things like return values, short circuit, or set flags (which would have alleviated things a bit, if it wasn't a violation of the no non-final variables rule). "This is not just an optimization, but critical when you consider that some sequences (like reading the lines in a file) may have side-effects, or you may have an infinite sequence."Might execute in parallel, which is a horrible, horrible thing for all but the 0.1% of your code that needs to be optimized. Any parallel code has to be thought through (even if it doesn't use locks, volatiles, and other particularly nasty aspects of traditional multi-threaded execution). Any bug will be tough to find.
Might hurt performance, because the JIT can't optimize forEach()+lambda to the same extent as plain loops, especially now that lambdas are new. By "optimization" I do not mean the overhead of calling lambdas (which is small), but to the sophisticated analysis and transformation that the modern JIT compiler performs on running code.
If you do need parallelism, it is probably much faster and not much more difficult to use an ExecutorService. Streams are both automagical (read: don't know much about your problem) and use a specialized (read: inefficient for the general case) parallelization strategy (fork-join recursive decomposition).
Makes debugging more confusing, because of the nested call hierarchy and, god forbid, parallel execution. The debugger may have issues displaying variables from the surrounding code, and things like step-through may not work as expected.
Streams in general are more difficult to code, read, and debug. Actually, this is true of complex "fluent" APIs in general. The combination of complex single statements, heavy use of generics, and lack of intermediate variables conspire to produce confusing error messages and frustrate debugging. Instead of "this method doesn't have an overload for type X" you get an error message closer to "somewhere you messed up the types, but we don't know where or how." Similarly, you can't step through and examine things in a debugger as easily as when the code is broken into multiple statements, and intermediate values are saved to variables. Finally, reading the code and understanding the types and behavior at each stage of execution may be non-trivial.
Sticks out like a sore thumb. The Java language already has the for-each statement. Why replace it with a function call? Why encourage hiding side-effects somewhere in expressions? Why encourage unwieldy one-liners? Mixing regular for-each and new forEach willy-nilly is bad style. Code should speak in idioms (patterns that are quick to comprehend due to their repetition), and the fewer idioms are used the clearer the code is and less time is spent deciding which idiom to use (a big time-drain for perfectionists like myself!).
As you can see, I'm not a big fan of the forEach() except in cases when it makes sense.
Particularly offensive to me is the fact that Stream does not implement Iterable (despite actually having method iterator) and cannot be used in a for-each, only with a forEach(). I recommend casting Streams into Iterables with (Iterable<T>)stream::iterator. A better alternative is to use StreamEx which fixes a number of Stream API problems, including implementing Iterable.
That said, forEach() is useful for the following:
Atomically iterating over a synchronized list. Prior to this, a list generated with
Collections.synchronizedList()was atomic with respect to things like get or set, but was not thread-safe when iterating.Parallel execution (using an appropriate parallel stream). This saves you a few lines of code vs using an ExecutorService, if your problem matches the performance assumptions built into Streams and Spliterators.
Specific containers which, like the synchronized list, benefit from being in control of iteration (although this is largely theoretical unless people can bring up more examples)
Calling a single function more cleanly by using
forEach()and a method reference argument (ie,list.forEach (obj::someMethod)). However, keep in mind the points on checked exceptions, more difficult debugging, and reducing the number of idioms you use when writing code.
Articles I used for reference:
- Everything about Java 8
- Iteration Inside and Out (as pointed out by another poster)
EDIT: Looks like some of the original proposals for lambdas (such as http://www.javac.info/closures-v06a.html Google Cache) solved some of the issues I mentioned (while adding their own complications, of course).
The advantage comes into account when the operations can be executed in parallel. (See http://java.dzone.com/articles/devoxx-2012-java-8-lambda-and - the section about internal and external iteration)
The main advantage from my point of view is that the implementation of what is to be done within the loop can be defined without having to decide if it will be executed in parallel or sequential
If you want your loop to be executed in parallel you could simply write
joins.parallelStream().forEach(join -> mIrc.join(mSession, join));You will have to write some extra code for thread handling etc.
Note: For my answer I assumed joins implementing the java.util.Stream interface. If joins implements only the java.util.Iterable interface this is no longer true.