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.
Related
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.
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.
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.
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
So I have a method (of which I can't change the parameters, or else this could have been made easier through HashMaps...more on this later), that passes an item as a parameter. Now I have a list of instances from this other class, of which one of its attributes is of the same type of this item, and I want to find the instances in the list which correspond to this item (of which there should be only one). This is what I did to find this:
List<Instance> instances = ...
public static void checkItems(Item i) {
List<Instance> n = new ArrayList<>();
instances.forEach(p -> n.add(p.i == i ? p : null));
Instance currentInstance = n.get(0);
//Instance currentInstance = instances.stream().filter(p -> p.i == i).collect(Collectors.toList()).get(0);
}
You'll probably notice two things straight up:
I used a conditional operator which adds a null value to the list when the condition isn't passed
My commented code which was another attempt to solve this issue
So in the first case, I put null because it requires you to put something, and a null value is probably easier to work with, which is why the question arises: How do I access the first non-null value in a list (without resorting to iterating over the entire list to find it...)?
You may notice that I just assign the first value of the list with n.get(0) to currentInstance, because I know that only one value will have passed the test. However, due to some other code that I apply to currentInstance, this value cannot be null.
Just a note on the second point: the way I tried to solve it with streams actually works exactly as planned, except that for some reason the list of instances recovered is not a direct copy of the original instances. This resulted in the values of some of the attributed to have been reset to default values, therefore rendering this method useless.
EDIT: I just wanted to mention that the streams method wasn't working because of some silly mistake that I made in another class, there was nothing wrong with the code so I'll be using that bit to solve my problem :D
If you know that only one p passes the test, I don't know what the point of creating a list with a load of null values plus p is.
Your problem seems to stem from wanting to use forEach. In my opinion, you should almost always use a for loop in preference to forEach. With a simple for loop you can just use break when the item is found.
In detail:
Instance p = null;
for (Instance q : instances) {
if (q.i == i) {
p = q;
break;
}
}
if (p == null)
throw new IllegalStateException(); // It wasn't there.
// Do something with p.
You could do it this way:
Instance currentInstance = instances.stream()
.filter(p -> p.i == i)
.findFirst()
.get(); // you can use get if you are sure there's one instance
The predicate p -> p.i == i seems suspicious. Why not using equals() instead?
As described, this would normally be solved with streams in the following way:
Optional<Instance> first =
instances.stream().filter(p -> p.i == i).findFirst();
(of which there should be only one)
Of which there definitely is only one, or of which there might be more than one. (And if there's more than one, then what? Is that an error?) It sounds like it might be that you should have a Set<Instance>, not a List<Instance>. Just an observation.
You can do it like
instances.forEach(p -> {
if (p.i == i) n.add(p);
});