This question already has answers here:
In Java, how do I efficiently and elegantly stream a tree node's descendants?
(5 answers)
Closed 6 years ago.
I was asked to retrieve every leaf node that is a descandant of a tree node. I quickly got the idea that I could do this job in one line!
public Set<TreeNode<E>> getLeaves() {
return getChildrenStream().flatMap(n -> n.getChildrenStream()).collect(toSet());
}
It was good at the first glance, but quickly it ran into a StackOverflowExcepetionif the tree depth reaches ~10, something that I can't accept. Later I developed a implementation without recursion and stream (but with my brain roasted), but I'm still wondering if there is a way to do recursive flatMaps with stream, because I found it impossible to do so without touching the stream internals. It'll need a new Op, like RecursiveOps to do that, or I will have to collect all results into a Set every step, and operate on that Set later:
Set<TreeNode<E>> prev = new HashSet<>();
prev.add(this);
while (!prev.isEmpty()) {
prev = prev.stream().flatMap(n -> n.getChildrenStream()).collect(toSet());
}
return prev;
Not good as it seems to be. Streams are meant to be a pipeline. Its result and intermediate results are not computed until a terminal op is added. The above approach appearently violates that principle. It's not as easy to parellelize as streams, too. Can I recursively flatMap without manually computing all intermediate results?
PS1: the TreeNode declaration:
public class TreeNode<E> {
// ...
/**
* Get a stream of children of the current node.
*
*/
public Stream<TreeNode<E>> getChildrenStream(){
// ...
}
public Set<TreeNode<E>> getLeaves() {
// main concern
}
}f
Not entirely sure if this would be something that you would be interested in:
public static Set<TreeNode<String>> getAllLeaves(TreeNode<String> treeNode) {
final Stream<TreeNode<String>> childrenStream = treeNode.getChildrenStream();
if (childrenStream == null) {
return new HashSet<>();
}
Set<TreeNode<String>> ownLeaves = treeNode.getLeaves();
ownLeaves.addAll(childrenStream.flatMap(stringTreeNode -> getAllLeaves(stringTreeNode).parallelStream())
.collect(Collectors.toSet()));
return ownLeaves;
}
Out of the box I see a few inconvenients with this method. It does return an empty Set for the last iteration and It's creating streams as it does the flatMap. However I believe this is what you are looking for, since you are thinking about using flatMap from where you want to get a joined Set created recursively where no stream was created in the first place. Btw, I've tried this with a -1000 level and it still works quite fast and with no problem.
Related
I have a POJO:
class MyObject {
private Double a;
private String b;
//constructor, getter + setter
}
Some function is creating a list of this POJO. Some values for a might be null, so I want to replace them with 0.0. At the moment I am doing it like this.
public List<MyObject> fetchMyObjects(Predicate predicate) {
List<MyObject> list = getMyListsOfTheDatabase(predicate);
list
.forEach(myObject -> {
if (myObject.getA() == null) {
myObject.setA(0.0);
}
});
return list;
}
Is there a way to integrate the forEach in the return? Something like
return list
.stream()
.someStatement();
It's not about, if this is the best place to convert the nulls to zero, but rather a questions to better understand the streaming api.
Use the peek function
Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
public List<MyObject> fetchMyObjects(Predicate predicate) {
return getMyListsOfTheDatabase(predicate)
.stream()
.peek(it -> if(it.getA() == null) it.setA(0.0))
.collect(Collectors.toList());
}
While others have been happy to answer your question as it stands, allow me to step a step back and give you the answer you didn’t ask for (but maybe the answer that you want): You don’t want to do that. A stream operation should be free from side effects. What you are asking for is exactly a stream operation that has the side effect of modifying the original objects going into the stream. Such is poor code style and likely to confuse those reading your code after you.
The code you already have solves your problem much more nicely than any combined stream pipeline.
What you may want to have if you can modify your POJO is either a constructor that sets a to 0 if null was retrieved from the database, or method that does it that you may call from list.forEach:
list.forEach(MyObject::setAToZeroIfNull);
It's not about, if this is the best place to convert the nulls to
zero, but rather a questions to better understand the streaming api.
That’s fair. In any case I will let this answer stand for anyone else popping by.
You can't return the same List instance with a single statement, but you can return a new List instance containing the same (possibly modified) elements:
return list.stream()
.map(myObject -> {
if (myObject.getA() == null) {
myObject.setA(0.0);
}
return myObject;
})
.collect(Collectors.toList());
Actually you should be using List::replaceAll:
list.replaceAll(x -> {
if(x.getA() == null) x.setA(0.0D);
return x;
})
forEach doesn't have a return value, so what you might be looking for is map
return list
.stream()
.map(e -> {
if (e.getA() == null) e.setA(0d);
return e;
})
.whateverElse()...
The following would be fine:
list.stream()
.filter(obj -> obj.getA() == null)
.forEach(obj -> obj.setA(0.0));
return list;
However in your case just returning a Stream might be more appropriate (depends):
public Stream<MyObject> fetchMyObjects(Predicate predicate) {
return getMyListsOfTheDatabase(predicate);
}
public Stream<MyObject> streamMyObjects(List<MyObject> list) {
return list.stream()
.peek(obj -> {
if (obj.getA() == null) {
obj.setA(0.0);
}
});
}
I personally never used peek, but here it corrects values.
On code conventions, which are more string in the java community:
Indentation: Java took 4 as opposed to C++'s 3 as more separate methods,
and less indentation was expected. Debatable but okay.
For generic type parameters often a single capital like T, C, S.
For lambda parameters short names, often a single letter, hence I used obj.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Some background: I am new to Java and am taking a basic java class. I am currently on the final project for the class and completed everything except for this last bit of code. For some reason, I am having the toughest time deleting an element from an array list. Here is the code I am working on:
public static void delete(String bookID) {
for (book eachElement : catalog) {
if (eachElement.getBookID().equals(bookID)) {
catalog.remove(eachElement);
return;
}
}
}
code executes, no run time errors but it won't delete anything.
also, I know everything works prior to the remove statement because I have another method that computes calculations using the same exact for and if statement with a select bookID string.
You should not and cannot remove an Element from a Collection while being in a forEach loop.
Please read the Documentation for ArrayList in Java.
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
There you actually can see, that ArrayList.remove(Object o), removes o if it is in the list, so your method is not needed.
So the answer is, find the book Object with your ID and then remove it. Or better use a Map to store your data.
In your case it would be
Book b = null;
for(Book book : books) {
if(book.getBookId().equals(bookId)) {
b = book.getBookId();
break;
}
}
books.remove(b);
Or if you are into Java8 which you really should be :D
books.stream().filter(b -> b.getBookId().equals(bookId)).getFirst().ifPresent(books::remove);
You need to use iterator, otherwise you will get java.util.ConcurrentModificationException
public static void delete(String bookID) {
for (Iterator<Book> it = catalog.listIterator(); it.hasNext(); ) {
Book book = it.next();
if (book.getBookID().equalsIgnoreCase(bookID)) {
it.remove(book);
return;
}
}
}
Note: equalsIgnoreCase is used to discard case differences.
java.util.ConcurrentModificationException is thrown, because you are doing 2 operations on the list: iteration and removal. So, actually, there is another approach - copy the list on each step of iteration.
public static void delete(String bookID) {
for (Book book : new ArrayList<>(catalog)) {
if (book.getBookID().equalsIgnoreCase(bookID)) {
catalog.remove(book);
return;
}
}
}
Note: Because of performance considerations (quadratic memory usage and linear removal on each step), I don't recommend the last approach. I give this example only to stress out the underlying reason why java.util.ConcurrentModificationException is thrown.
Removal of elements, while an iterator is being used, is undefined.The better approach would be to use removeIf.
catalog.removeIf(eachElement -> eachElement.getBookID().equals(bookId));
You need to use iterator in order to delete item while using loop .
also double check if the id exist (make some System.out.println("test") and check if it is entering the scope).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Java 8 provides a bunch of functional interfaces that we can implement using lambda expressions, which allows functions to be treated as
first-class citizen (passed as arguments, returned from a method, etc...).
Example:
Stream.of("Hello", "World").forEach(str->System.out.println(str));
Why functions considered as first-class citizens are so important? Any example to demonstrate this power?
The idea is to be able to pass behavior as a parameter. This is useful, for example, in implementing the Strategy pattern.
Streams API is a perfect example of how passing behavior as a parameter is useful:
people.stream()
.map(person::name)
.map(name->new GraveStone(name, Rock.GRANITE)
.collect(Collectors.toSet())
Also it allows programmers to think in terms of functional programming instead of object-oriented programming, which is convenient for a lot of tasks, but is quite a broad thing to cover in an answer.
I think the second part of the question has been addressed well. But I want to try to answer the first question.
By definition there is more that a first-class citizen function can do. A first-class citizen function can:
be named by variables
be passed as arguments
be returned as the result of another function
participate as a member data type in a data structure (e.g., an array or list)
These are the privileges of being "first-class."
It's a matter of expressiveness. You don't have to, but in many practical cases it will make your code more readable and concise. For instance, take your code:
public class Foo {
public static void main(String[] args) {
Stream.of("Hello", "World").forEach(str->System.out.println(str));
}
}
And compare it to the most concise Java 7 implementation I could come out with:
interface Procedure<T> {
void call(T arg);
}
class Util {
static <T> void forEach(Procedure<T> proc, T... elements) {
for (T el: elements) {
proc.call(el);
}
}
}
public class Foo {
static public void main(String[] args) {
Util.forEach(
new Procedure<String>() {
public void call(String str) { System.out.println(str); }
},
"Hello", "World"
);
}
}
The result is the same, the number of lines a bit less :) Also note that for supporting Procedure instances with different number of arguments, you would have needed an interface each or (more practical) passing all the arguments as a single Parameters object. A closures would have been made in a similar way, by adding some fields to the Procedure implementation. That's a lot of boilerplate.
In fact, things like first-class "functors" and (non-mutable) closures have been around for a long time using anonymous classes, but they required a significant implementation effort. Lambdas just make things easier to read and write (at least, in most cases).
Here's a short program the shows (arguably) the primary differentiating factor.
public static void main(String[] args) {
List<Integer> input = Arrays.asList(10, 12, 13, 15, 17, 19);
List<Integer> list = pickEvensViaLists(input);
for (int i = 0; i < 2; ++i)
System.out.println(list.get(i));
System.out.println("--------------------------------------------");
pickEvensViaStreams(input).limit(2).forEach((x) -> System.out.println(x));
}
private static List<Integer> pickEvensViaLists(List<Integer> input) {
List<Integer> list = new ArrayList<Integer>(input);
for (Iterator<Integer> iter = list.iterator(); iter.hasNext(); ) {
int curr = iter.next();
System.out.println("processing list element " + curr);
if (curr % 2 != 0)
iter.remove();
}
return list;
}
private static Stream<Integer> pickEvensViaStreams(List<Integer> input) {
Stream<Integer> inputStream = input.stream();
Stream<Integer> filtered = inputStream.filter((curr) -> {
System.out.println("processing stream element " + curr);
return curr % 2 == 0;
});
return filtered;
}
This program takes an input list and prints the first two even numbers from it. It does so twice: the first time using lists with hand-written loops, the second time using streams with lambda expressions.
There are some differences in terms of the amount of code one has to write in either approach but this is not (in my mind) the main point. The difference is in how things are evaluated:
In the list-based approach the code of pickEvensViaLists() iterates over the entire list. it will remove all odd values from the list and only then will return back to main(). The list that it returned to main() will therefore contain four values: 10, 12, 20, 30 and main() will print just the first two.
In the stream-based approach the code of pickEvensViaStreams() does not actually iterate over anything. It returns a stream who else can be computed off of the input stream but it did not yet compute any one of them. Only when main() starts iterating (via forEach()) will the elements of the returned stream be computed, one by one. As main() only cares about the first two elements only two elements of the returned stream are actually computed. In other words: with stream you get lazy evaluation: streams are iterated only much as needed.
To see that let's examine the output of this program:
--------------------------------------------
list-based filtering:
processing list element 10
processing list element 12
processing list element 13
processing list element 15
processing list element 17
processing list element 19
processing list element 20
processing list element 30
10
12
--------------------------------------------
stream-based filtering:
processing stream element 10
10
processing stream element 12
12
with lists the entire input was iterated over (hence the eight "processing list element" messages). With stream only two elements were actually extracted from the input resulting in only two "processing stream element" messages.
This question already has answers here:
Limit a stream by a predicate
(19 answers)
Closed 8 years ago.
I have a set and a method:
private static Set<String> set = ...;
public static String method(){
final String returnVal[] = new String[1];
set.forEach((String str) -> {
returnVal[0] += str;
//if something: goto mark
});
//mark
return returnVal[0];
}
Can I terminate the forEach inside the lambda (with or without using exceptions)?
Should I use an anonymous class?
I could do this:
set.forEach((String str) -> {
if(someConditions()){
returnVal[0] += str;
}
});
but it wastes time.
implementation using stream.reduce
return set.parallelStream().reduce((output, next) -> {
return someConditions() ? next : output;
}).get(); //should avoid empty set before
I am looking for the fastest solution so exception and a 'real' for each loop are acceptable if they are fast enough.
I'm reluctant to answer this even though I'm not entirely sure what you're attempting to accomplish, but the simple answer is no, you can't terminate a forEach when it's halfway through processing elements.
The official Javadoc states that it is a terminal operation that applies against all elements in the stream.
Performs an action for each element of this stream.
This is a terminal operation.
If you want to gather the results into a single result, you want to use reduction instead.
Be sure to consider what it is a stream is doing. It is acting on all elements contained in it - and if it's filtered along the way, each step in the chain can be said to act on all elements in its stream, even if it's a subset of the original.
In case you were curious as to why simply putting a return wouldn't have any effect, here's the implementation of forEach.
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
The consumer is explicitly passed in, ad this is done independently of the actual iteration going on. I imagine you could throw an exception, but that would be tacky when more elegant solutions likely exist.
I have written a code for deleting all elements of tree.
Need suggestions for following:
In reverseTreeStack method, Can I design without using stack method parameter?
Can I design the entire code in 1 method with better design?
UPDATE : Changed return type of reverseTreeStack to void.Removed additional variable for stack.
public class DeleteTree {
public static void deleteTree(BinaryTreeNode root)
{
Stack stack = new Stack();
reverseTreeStack(stack, root);
while (!stack.isEmpty())
{
BinaryTreeNode node = (BinaryTreeNode)stack.pop();
System.out.println("---------Deleting----------->" + node.getData());
node = null;
}
}
public static void reverseTreeStack(Stack stack,BinaryTreeNode root)
{
if (root != null)
{
stack.push(root);
reverseTreeStack(stack,root.getLeft());
reverseTreeStack(stack, root.getRight());
}
}
}
Why do you need to do this? If I recall correctly, the JVM can free resources once there are no available references to the resource, so just setting your root node to be null should free the whole tree.
I think, James is right, but if you want to practice the tree traversal, or if you want to implement this in a language where you need to free memory manually, then use recursion:
void deleteTree(TreeNode node)
{
if(node==null)return;
deleteTree(node.getLeft());
deleteTree(node.getRight());
System.out.printline("Deleting: "+node.getData())
node = null;
}
Also take a look at Postorder Traversal (thats the only one, that works for deleting)
1) I think you can kill the return value and make it a void method as you are directly manipulating the stack. So just do
Stack stack = new Stack();
reverseTreeStack(stack, root);
// Now just use stack
2) Don't condense things into one method. Breaking things out into more methods will make your code easier to navigate and understand. The less each function is responsible for, the more sense it will make to someone reading it.
Well your reverseTreeStack method can potentially give you a StackOverflowError if your tree is too large, so using a loop instead of recursion there might be a better choice (unless you know for a fact that your trees will never be that large).
Also, why are you "deleting" every node? (node = null actually just removes the reference you have just in that method...) Generally just forgetting the root (root = null) will delete your whole tree if you're structuring it in the classic way of Node(parent, leftChild, rightChild) and not storing pointers to nodes anywhere else.