Java Stream .map ternary operator - java

I have a TXT.File with Lines which are representing some Objects
R-Line (one)
RN-Line (1...many)
they are connected with id so in order to read the file I made a lines().stream
Stream<Boolean> inLines = in.lines()
//limit lines due to memory footprint
.limit(10)
//filter each line by the given id
.filter(identN -> ident.matches(".*\\t[5]\\t.*"))
/**
* should return all lines with id 5
* if line starts with RN put it in rnArray else in rArray so the objects are connected but i need for validation purposes each line seperate??
*/
.map(y -> (y.startsWith("RN") ? synonym1.add(y) : substance.add(y)));
System.out.println("syn1 = " + synonym1.toString() + "substance: = " + substance + " InLines"+ inLines);
Response is empty :
syn1 = []substance: = [] InLinesjava.util.stream.ReferencePipeline$3#3aa9e816
But it doesn't work. The return of the .map should be another stream so how can I incorporate this logic if I use for each it won't work since I need also the r-Line.

Cause
The response is empty since there is no terminal operation invoked on the Stream that you've created(inLines). Hence both synonym1 and substance remain empty while you try to access them while printing to the console.
Alternate
What you might just be looking for is to replace the final map operation with a forEach, since it would persist both synonym1 and substance types of elements found which seems to be your primary use case. This can be done as:
.forEach(y -> {
if (y.startsWith("RN")) {
synonym1.add(y);
} else {
substance.add(y);
}
});
Note
Currently, it doesn't make much sense to collect the Stream<Boolean> into a Collection, since that would include the result of .add operation on the synonym1 and substance collections for each filtered element.

Thanks #Naman, it helped me alot since i found a way that allows me too use the ternary operator and split the stream into 2 seperate Lists by grouping the
.forEach((x) -> ((x.startsWith("RN"))?synonym:substance).add(x));
so the problem is that the x operator was not in brackets i think it is because
grouping objects or is there any other explaination
Thanks

Related

ConcurrentHashMap throws recursive update exception

Here is my Java code:
static Map<BigInteger, Integer> cache = new ConcurrentHashMap<>();
static Integer minFinder(BigInteger num) {
if (num.equals(BigInteger.ONE)) {
return 0;
}
if (num.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
//focus on stuff thats happening inside this block, since with given inputs it won't reach last return
return 1 + cache.computeIfAbsent(num.divide(BigInteger.valueOf(2)),
n -> minFinder(n));
}
return 1 + Math.min(cache.computeIfAbsent(num.subtract(BigInteger.ONE), n -> minFinder(n)),
cache.computeIfAbsent(num.add(BigInteger.ONE), n -> minFinder(n)));
}
I tried to memoize a function that returns a minimum number of actions such as division by 2, subtract by one or add one.
The problem I'm facing is when I call it with smaller inputs such as:
minFinder(new BigInteger("32"))
it works, but with bigger values like:
minFinder(new BigInteger("64"))
It throws a Recursive Update exception.
Is there any way to increase recursion size to prevent this exception or any other way to solve this?
From the API docs of Map.computeIfAbsent():
The mapping function should not modify this map during computation.
The API docs of ConcurrentHashMap.computeIfAbsent() make that stronger:
The mapping function must not modify this map during computation.
(Emphasis added)
You are violating that by using your minFinder() method as the mapping function. That it seems nevertheless to work for certain inputs is irrelevant. You need to find a different way to achieve what you're after.
Is there any way to increase recursion size to prevent this exception or any other way to solve this?
You could avoid computeIfAbsent() and instead do the same thing the old-school way:
BigInteger halfNum = num.divide(BigInteger.valueOf(2));
BigInteger cachedValue = cache.get(halfNum);
if (cachedValue == null) {
cachedValue = minFinder(halfNum);
cache.put(halfNum, cachedValue);
}
return 1 + cachedValue;
But that's not going to be sufficient if the computation loops. You could perhaps detect that by putting a sentinel value into the map before you recurse, so that you can recognize loops.

Assign a value based on condition using Java Stream if present or else

I want to set a value to a string if an Optional is present else get it from a list based on a condition. I have tried many ways but not able to get it. I am new to Streams so need help.
Basically my condition is this in traditional way -
String rel = ""
if(release.isPresent()){
rel = release.get();
}
else{
for(Release r: project.getReleases()){
if(r.isActive() == true){
rel = r.getName();
}
}
}
This is what I have written, but it doesn't work. I am getting error in the orElse part -
rel = release.ifPresent(r-> release.get())
.orElse(
project.getReleases()
.stream()
.filter( r -> r.isActive() == true)
.findFirst()
.map(r->r.getName()));
Can you please suggest what is the correct way to do this ? Thanks in advance for any help.
This is what you want in case you use java-9 or newer (I recommend you to tag the version used):
String rel = release
.or(() -> project.getReleases().stream()
.filter(Release::isActive)
.map(Release::getName)
.findFirst())
.orElse("");
Basically Optional#or returns either the present value from the original Optional or provides a Supplier<Optional> providing such value in lazy way (will not be called in case the former value is present).
Use the advantage that Stream#findFirst returns Optional hence such call is compatible with the method needs. Finally call orElse("") as the last possible value if no usable value was present in the previous attempts.
You should use Optional#orElseGet for this
Why orElseGet and not orElse ?
Because orElseGet accepts a Supplier which will only be invoked if your Optional is empty. So you won't have the overhead of Stream creation etc.
Example
String rel = release.orElseGet(() -> project.getReleases()
.stream()
.filter(Release::isActive)
.map(Release::getName)
.findFirst()
.orElse(""));
you can do
release.orElse(project.getReleases()
.stream().filter(Release::isActive).findFirst().map(Release::getName).orElse(""));

Nested parallel stream execution in Java - findAny() randomly fails

The following code throws the IllegalArgumentException in every 10-15 try for the same input:
AllDirectedPaths<Vertex, Edge> allDirectedPaths = new AllDirectedPaths<>(graph);
List<GraphPath<Vertex, Edge>> paths = allDirectedPaths.getAllPaths(entry, exit, true, null);
return paths.parallelStream().map(path -> path.getEdgeList().parallelStream()
.map(edge -> {
Vertex source = edge.getSource();
Vertex target = edge.getTarget();
if (source.containsInstruction(method, instructionIndex)) {
return source;
} else if (target.containsInstruction(method, instructionIndex)) {
return target;
} else {
return null;
}
}).filter(Objects::nonNull)).findAny().flatMap(Stream::findAny)
.orElseThrow(() -> new IllegalArgumentException("Given trace refers to no vertex in graph!"));
The idea of the code is to find a vertex that wraps a certain instruction (see containsInstruction()), whereas the vertex is on at least one path from the entry to the exit vertex. I'm aware that the code is not optimal in terms of performance (every intermediate vertex on a path is looked up twice), but that doesn't matter.
The input is simply a trace (String) from which the method and instructionIndex can be derived. All other variables are fixed in that sense. Moreover, the method containsInstruction() doesn't have any side effects.
Does it matter where to put the 'findAny()' stream operation? Should I place it directly following the filter operation? Or are nested parallel streams the problem?
You should use .flatMap(path -> ... ) and remove .flatMap(Stream::findAny).
Your code doesn't work because the first findAny() returns a stream that is always non null, but that might hold null elements.
Then, when you apply the second findAny() by means of the Optional.flatMap(Stream::findAny) call, this last find operation might return an empty Optional, as the result of ending up with a null element of the inner stream.
This is how the code should look:
return paths.stream()
.flatMap(path -> path.getEdgeList().stream()
.map(edge ->
edge.getSource().containsInstruction(method, instructionIndex) ?
edge.getSource() :
edge.getTarget().containsInstruction(method, instructionIndex) ?
edge.getTarget() :
null)
.filter(Objects::nonNull))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("whatever"));
Note aside: why parallel streams? There doesn't seem to be CPU bound tasks in your pipeline. Besides, parallel streams create a lot of overhead. They are useful in very few scenarios, i.e. tens of thousands of elements and intensive CPU operations along the pipeline
EDIT: As suggested in the comments, the map and filter operations of the inner stream could be safely moved to the outer stream. This way, readability is improved and there's no difference performance-wise:
return paths.stream()
.flatMap(path -> path.getEdgeList().stream())
.map(edge ->
edge.getSource().containsInstruction(method, instructionIndex) ?
edge.getSource() :
edge.getTarget().containsInstruction(method, instructionIndex) ?
edge.getTarget() :
null)
.filter(Objects::nonNull)
.findAny()
.orElseThrow(() -> new IllegalArgumentException("whatever"));
Another note: maybe refactoring the code inside map to a method of the Edge class would be better, so that the logic to return either the source, the target or null is in the class that already has all the information.

Compare String with each element of a String Array using Streams

Hi i want to count how many time a String is found in a Array of Strings using Streams
What i have thought so far is this:
Stream<String> stream=Arrays.stream(array);
int counter= (int) stream.filter(c-> c.contains("something")).count();
return counter;
The problem that i get is that most of the time i get an error of NullPointerException and i think is because of .count() if it doesn't get any much inside filter(c-> c.contains("something")).
And i came to this conclusion cause if i run it with out .count() like that stream.filter(c-> c.contains("something")); without returning nothing, it won't throw an Exception. I'm not sure about it but that's what i think.
Any ideas on how i can count the times a String appears in and Array of Strings using Streams?
null is a valid element of an array, so you have to be prepared to handle these. For example:
int counter = stream.filter(c -> c != null && c.contains("something")).count();
The problem that i get is that most of the time i get an error of
NullPointerException and i think is because of .count() And i came to
this conclusion cause if i run it with out .count()
it won't throw an Exception.
The reason being you cannot replicate the NullPointerException without calling count is because streams are lazy evaluated i.e. the entire pipeline is not executed until an eager operation (an operation which triggers the processing of the pipeline) is invoked.
We can come to the conclusion that Arrays.stream(array) is not the culprit for the NullPointerException because it would have blown up regardless of wether you called an eager operation on the stream or not as the parameter to Arrays.stream should be nonNull or else it would bomb out with the aforementioned error.
Thus we can come to the conclusion that the elements inside the array are the culprits for this error in the code you've illustrated but then you should ask your self are null elements allowed in the first place and if so then filter them out before performing c.contains("something") and if not then you should debug at which point in your application were nulls added to the array when they should not be. find the bug rather than suppress it.
if null's are allowed in the first place then the solution is simple i.e. filter the nulls out before calling .contains:
int counter = (int)stream.filter(Objects::nonNull)
.filter(c -> c.contains("something")) // or single filter with c -> c != null && c.contains("something") as pred
.count();
You have to filter for null values first. Do it either the way #pafauk. answered or by filtering sepraretly. That requires the null filter to be applied before the one you already use:
public static void main(String[] args) {
List<String> chainedChars = new ArrayList<>();
chainedChars.add("something new"); // match
chainedChars.add("something else"); // match
chainedChars.add("anything new");
chainedChars.add("anything else");
chainedChars.add("some things will never change");
chainedChars.add("sometimes");
chainedChars.add(null);
chainedChars.add("some kind of thing");
chainedChars.add("sumthin");
chainedChars.add("I have something in mind"); // match
chainedChars.add("handsome thing");
long somethings = chainedChars.stream()
.filter(java.util.Objects::nonNull)
.filter(cc -> cc.contains("something"))
.count();
System.out.printf("Found %d somethings", somethings);
}
outputs
Found 3 somethings
while switching the filter lines will result in a NullPointerException.

How to apply Java Stream for existing forEach loop with if condition

I am new to Java stream and can use java stream on ArrayList. This time I don't have any clue and been trying since 2 hours. I am not getting any idea. I am not sure even if it is possible to use Java stream here. Can someone please guide me? I don't even know where to start. How shall I check for below condition transactions.getAvatarInfo() != null?
This for loop works as expected. and I need to use Java Streams here instead of for loop. I was able to use Java Streams at other for loops , it was straight forward. Here I don't even know where to start.
for (int i = 0; i < accountInfo.get().getTransactions().size(); i++) {
Transactions transactions = accountInfo.get().getTransactions().get(i);
AvatarInfo avatarInfo = new AvatarInfo ();
if (transactions.getAvatarInfo() != null) {
transations.setAvataruri(TransactionsConstant.PREFIX +
transactions.getAvatarInfo().getUserName().toLowerCase());
transactions.getAvatarInfo().setUserName(transactions.getAvatarInfo ().getUsername());
}
}
So far I have tried below but it gives error saying ; is expeccted after null. And if I add that there would be another error.
accountInfo.get().getTransactions().stream().filter(a -> {
AvatarInfo avatarInfo = new AvatarInfo ();
a.getAvatarInfo() != null
})
If you have only a single expression, you can write a lambda using just that expression, like this:
a -> (a.getAvatarInfo() != null) // returns a boolean for filter
However, when you introduce {}, you have a full embedded method that has to follow all the normal syntax for a method. In this case, since your lambda should return a boolean, you need
return a.getAvatarInfo() != null;
However, the new AvatarInfo() business appears to be completely unnecessary and can be removed, allowing you to use the simpler form.
ArrayList is a Collection. Since Java 8 Collection defines a stream() method which will return a Stream of the elements of your ArrayList.
See https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream--
To get the list we need a collector, so I think it should be like this:
transactions.stream()
.filter(account -> account.getAvatarInfo() != null)
.collect(Collectors.toList());
Otherwise it will only return a Stream instead of a List.

Categories