I want to refactor this code to use lambda expression java 8
for(int i = 0; i < customers.getCUSTOMER().size(); i++){
if (customers.getCUSTOMER().get(i).getINCOME().getGROSSMONTH1().toBigInteger()
< customers.getCUSTOMER().get(i).getINCOME().getNETTSALMONTH1().toBigInteger()){
log.error("")
throw new RuntimeException();
}
}
You are iterating over the elements of customers.getCUSTOMER(), which appears to be a List (and I assume for the purposes of this answer that it is one). Presumably, then, you're going to process that list's stream:
customers.getCUSTOMER().stream()
you're using the getINCOME() of each element twice, and not any other aspect of it at all, so perhaps you want to map elements via that method. Supposing that the elements of the customer list are of type Customer, that might be
.map(Customer::getINCOME)
There are various ways to go from there, but since you're throwing an exception when a condition is satisfied, I'd personally go with Stream.anyMatch():
.anyMatch(x -> x.getGROSSMONTH1().toBigInteger().compareTo(
x.getNETTSALMONTH1().toBigInteger()) < 0)
That produces a boolean result that tells you whether any element satisfies the condition, and it stops looking as soon as it finds one that does (and the predicate for the anyMatch() is a lambda). You would use it in an if expression similar to the one you have now:
if (customers.getCUSTOMER().stream()
.map(Customer::getINCOME)
.anyMatch(x -> x.getGROSSMONTH1().toBigInteger().compareTo(
x.getNETTSALMONTH1().toBigInteger()) < 0) {
log.error("")
throw new RuntimeException();
}
Since you're throwing a RuntimeException, it would also be possible to do that with a lambda, inside the stream, but that's not generally possible if you're throwing a checked exception. In the checked-exception case, something along the lines presented here is usually needful.
On the other hand, if you want to log information about the element that failed then you would need to do that inside the stream. Additionally, in that case you might want to skip the map(). You could instead filter() based on the predicate, and findFirst() among the elements, if any, remaining (or findAny() if you don't care whether it's the first that you report on). The result is an Optional, which you can process, if present, with another lambda:
customers.getCUSTOMER().stream()
.filter(x -> x.getINCOME().getGROSSMONTH1().toBigInteger().compareTo(
x.getINCOME().getNETTSALMONTH1().toBigInteger()) < 0)
.findFirst()
.ifPresent(x -> {
log.error(x.getName() + " invalid: net salary is larger than gross")
throw new RuntimeException();
});
Note that this does not solve the checked-exception problem. You cannot throw a checked exception from inside the ifPresent lambda.
customers.getCUSTOMER().stream().forEach(customer -> {
if(customer.getINCOME().getGROSSMONTH1().toBigInteger() < customer.getINCOME().getNETTSALMONTH1().toBigInteger()){
log.error("");
throw new RuntimeException();
}
});
You should also try renaming your methods using camelcase, e.g getIncome() to make it easier to read and conform to normal Java writing standards.
customers.getCUSTOMER().forEach(customer -> {
if (customer.getINCOME().getGROSSMONTH1().toBigInteger() <
customer.getINCOME().getNETTSALMONTH1().toBigInteger()) {
log.error("")
throw new RuntimeException();
}
});
A simple way
Another way using stream and Optional:
customers.stream().filter(customer ->
customer.getINCOME().getGROSSMONTH1().toBigInteger() <
customer.getINCOME().getNETTSALMONTH1().toBigInteger())
.findAny().ifPresent(c -> {
log.error("")
throw new RuntimeException();
});;
By using java-8 streams, use filter for condition and findFirst to terminate after one match
customers.getCUSTOMER().stream()
.filter(c->c.getINCOME().getGROSSMONTH1().toBigInteger() < c.getINCOME().getNETTSALMONTH1().toBigInteger())
.findFirst()
.ifPresent(cu->{
log.error("")
throw new RuntimeException();
});
What you need in this case is a BiPredicate<TypeOfMonths> which will look like this
BiPredicate<TypeOfMonths> biPredicate = (tom1, tom2) -> tom1.toBigInteger() < tom2.toBigInteger();
Then use it like this
boolean shouldThrowException = customers.getCUSTOMER()
.stream()
.anyMatch(cust -> {
TypeOfMonth tom1 = getINCOME().getGROSSMONTH1();
TypeOfMonth tom2 = getINCOME()..getNETTSALMONTH1();
return biPredicate.test(tom1, tom2);
});
if (shouldThrowException) {
log.error("");
throw new RuntimeException();
}
Related
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.
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.
Is method chaining good?
I am not against functional programming that uses method chaining a lot, but against a herd mentality where people mindlessly run behind something that is new.
The example, if I am processing a list of items using stream programming and need to find out the exact row that resulted into throwing NullPointerException.
private void test() {
List<User> aList = new ArrayList<>();
// fill aList with some data
aList.stream().forEach(x -> doSomethingMeaningFul(x.getAddress()));
}
private void doSomethingMeaningFul(Address x) {
// Do something
}
So in the example above if any object in list is null, it will lead to NullPointerException while calling x.getAddress() and come out, without giving us a hook to identify a User record which has this problem.
I may be missing something that offers this feature in stream programming, any help is appreciated.
Edit 1:
NPE is just an example, but there are several other RuntimeExceptions that could occur. Writing filter would essentially mean checking for every RTE condition based on the operation I am performing. And checking for every operation will become a pain.
To give a better idea about what I mean following is the snippet using older methods; I couldn't find any equivalent with streams / functional programming methods.
List<User> aList = new ArrayList<>();
// Fill list with some data
int counter = 0;
User u = null;
try {
for (;counter < aList.size(); counter++) {
u = aList.get(counter);
u.doSomething();
int result = u.getX() / u.getY();
}
} catch(Exception e) {
System.out.println("Error processing at index:" + counter + " with User record:" + u);
System.out.println("Exception:" + e);
}
This will be a boon during the maintenance phase(longest phase) pointing exact data related issues which are difficult to reproduce.
**Benefits:**
- Find exact index causing issue, pointing to data
- Any RTE is recorded and analyzed against the user record
- Smaller stacktrace to look at
Is method chaining good?
As so often, the simple answer is: it depends.
When you
know what you are doing
are be very sure that elements will never be null, thus the chance for an NPE in such a construct is (close to) 0
and the chaining of calls leads to improved readability
then sure, chain calls.
If any of the above criteria isn't clearly fulfilled, then consider not doing that.
In any case, it might be helpful to distribute your method calls on new lines. Tools like IntelliJ actually give you advanced type information for each line, when you do that (well, not always, see my own question ;)
From a different perspective: to the compiler, it doesn't matter much if you chain call. That really only matters to humans. Either for readability, or during debugging.
There are a few aspects to this.
1) Nulls
It's best to avoid the problem of checking for nulls, by never assigning null. This applies whether you're doing functional programming or not. Unfortunately a lot of library code does expose the possibility of a null return value, but try to limit exposure to this by handling it in one place.
Regardless of whether you're doing FP or not, you'll find you get a lot less frustrated if you never have to write null checks when calling your own methods, because your own methods can never return null.
An alternative to variables that might be null, is to use Java 8's Optional class.
Instead of:
public String myMethod(int i) {
if(i>0) {
return "Hello";
} else {
return null;
}
}
Do:
public Optional<String> myMethod(int i) {
if(i>0) {
return Optional.of("Hello");
} else {
return Optional.empty();
}
Look at Optional Javadoc to see how this forces the caller to think about the possibility of an Optional.empty() response.
As a bridge between the worlds of "null represents absent" and "Optional.empty() represents absent", you can use Optional.ofNullable(val) which returns Empty when val == null. But do bear in mind that Optional.empty() and Optional.of(null) are different values.
2) Exceptions
It's true that throwing an exception in a stream handler doesn't work very well. Exceptions aren't a very FP-friendly mechanism. The FP-friendly alternative is Either -- which isn't a standard part of Java but is easy to write yourself or find in third party libraries: Is there an equivalent of Scala's Either in Java 8?
public Either<Exception, Result> meaningfulMethod(Value val) {
try {
return Either.right(methodThatMightThrow(val));
} catch (Exception e) {
return Either.left(e);
}
}
... then:
List<Either<Exception, Result>> results = listOfValues.stream().map(meaningfulMethod).collect(Collectors.toList());
3) Indexes
You want to know the index of the stream element, when you're using a stream made from a List? See Is there a concise way to iterate over a stream with indices in Java 8?
In your test() function you are creating an emptylist List<User> aList = new ArrayList<>();
And doing for each on it. First add some element to
aList
If you want to handle null values you can add .filter(x-> x != null) this before foreach it will filter out all null value
Below is code
private void test() {
List<User> aList = new ArrayList<>();
aList.stream().filter(x-> x != null).forEach(x -> doSomethingMeaningFul(x.getAddress()));
}
private void doSomethingMeaningFul(Address x) {
// Do something
}
You can write a black of code in streams. And you can find out the list item which might result in NullPointerException. I hope this code might help
private void test() {
List<User> aList = new ArrayList<>();
aList.stream().forEach(x -> {
if(x.getAddress() != null)
return doSomethingMeaningFul(x.getAddress())
else
system.out.println(x+ "doesn't have address");
});
}
private void doSomethingMeaningFul(Address x) {
// Do something
}
If you want you can throw NullPointerException or custom excption like AddressNotFoundException in the else part
Currently our implementation of a base method using Set<String> clients was as follows -
if (clients.isEmpty()) {
throw new InvalidClientException();
}
for (String client : clients) {
if (!myMay.containsKey(client)) {
throw new InvalidClientException(client);
}
}
I tried converting it using lambda expression as follows -
clients.stream().filter(client -> !myMay.containsKey(client) || clients.isEmpty())
.forEach(InvalidClientException::new);
But this seems to be not working the same way, is the parameterised constructor call a miss here?
First of all, if the set is empty, the lambda passed to forEach won't be executed: an empty stream is empty, and filtering it won't add any element to it. Only potentially remove some.
Second, the lambda creates an exception. But it doesn't throw it.
You can use
if (clients.isEmpty() || clients.stream().anyMatch(client -> !myMay.containsKey(client))) {
throw new InvalidClientException();
}
EDIT: I missed the fact that you wanted to pass the (first?) client not in the set to the exception. To do that, you can do
if (clients.isEmpty()) {
throw new InvalidClientException();
}
clients.stream()
.filter(client -> !myMay.containsKey(client))
.findAny() // or .findFirst()
.ifPresent(client -> {
throw new InvalidClientException(client);
});
That will only work if the exception is a runtime exception, though, because you can't throw a checked exception from a Consumer. If it's a checked exception and you really want to keep it a checked exception, you can use
if (clients.isEmpty()) {
throw new InvalidClientException();
}
Optional<String> wrongClient =
clients.stream()
.filter(client -> !myMay.containsKey(client))
.findAny();
if (wrongClient.isPresent()) {
throw new InvalidClientException(wrongClient.get());
}
When using external iteration over an Iterable we use break or return from enhanced for-each loop as:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
How can we break or return using the internal iteration in a Java 8 lambda expression like:
someObjects.forEach(obj -> {
//what to do here?
})
If you need this, you shouldn't use forEach, but one of the other methods available on streams; which one, depends on what your goal is.
For example, if the goal of this loop is to find the first element which matches some predicate:
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findFirst();
(Note: This will not iterate the whole collection, because streams are lazily evaluated - it will stop at the first object that matches the condition).
If you just want to know if there's an element in the collection for which the condition is true, you could use anyMatch:
boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);
A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. You can just do a return to continue:
someObjects.forEach(obj -> {
if (some_condition_met) {
return;
}
})
This is possible for Iterable.forEach() (but not reliably with Stream.forEach()). The solution is not nice, but it is possible.
WARNING: You should not use it for controlling business logic, but purely for handling an exceptional situation which occurs during the execution of the forEach(). Such as a resource suddenly stops being accessible, one of the processed objects is violating a contract (e.g. contract says that all the elements in the stream must not be null but suddenly and unexpectedly one of them is null) etc.
According to the documentation for Iterable.forEach():
Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception... Exceptions thrown by the action are relayed to the caller.
So you throw an exception which will immediately break the internal loop.
The code will be something like this - I cannot say I like it but it works. You create your own class BreakException which extends RuntimeException.
try {
someObjects.forEach(obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
}
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
Notice that the try...catch is not around the lambda expression, but rather around the whole forEach() method. To make it more visible, see the following transcription of the code which shows it more clearly:
Consumer<? super SomeObject> action = obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
});
try {
someObjects.forEach(action);
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
Below you find the solution I used in a project. Instead forEach just use allMatch:
someObjects.allMatch(obj -> {
return !some_condition_met;
});
Update with Java 9+ with takeWhile:
MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
// doing something.
if (...) { // want to break;
ongoing.setFalse();
}
});
Either you need to use a method which uses a predicate indicating whether to keep going (so it has the break instead) or you need to throw an exception - which is a very ugly approach, of course.
So you could write a forEachConditional method like this:
public static <T> void forEachConditional(Iterable<T> source,
Predicate<T> action) {
for (T item : source) {
if (!action.test(item)) {
break;
}
}
}
Rather than Predicate<T>, you might want to define your own functional interface with the same general method (something taking a T and returning a bool) but with names that indicate the expectation more clearly - Predicate<T> isn't ideal here.
You can use java8 + rxjava.
//import java.util.stream.IntStream;
//import rx.Observable;
IntStream intStream = IntStream.range(1,10000000);
Observable.from(() -> intStream.iterator())
.takeWhile(n -> n < 10)
.forEach(n-> System.out.println(n));
For maximal performance in parallel operations use findAny() which is similar to findFirst().
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findAny();
However If a stable result is desired, use findFirst() instead.
Also note that matching patterns (anyMatch()/allMatch) will return only boolean, you will not get matched object.
I have achieved by something like this
private void doSomething() {
List<Action> actions = actionRepository.findAll();
boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
if (actionHasFormFields){
context.addError(someError);
}
}
}
private Predicate<Action> actionHasMyFieldsPredicate(){
return action -> action.getMyField1() != null;
}
You can achieve that using a mix of peek(..) and anyMatch(..).
Using your example:
someObjects.stream().peek(obj -> {
<your code here>
}).anyMatch(obj -> !<some_condition_met>);
Or just write a generic util method:
public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
stream.peek(consumer).anyMatch(predicate.negate());
}
And then use it, like this:
streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
<your code here>
});
int valueToMatch = 7;
Stream.of(1,2,3,4,5,6,7,8).anyMatch(val->{
boolean isMatch = val == valueToMatch;
if(isMatch) {
/*Do whatever you want...*/
System.out.println(val);
}
return isMatch;
});
It will do only operation where it find match, and after find match it stop it's iteration.
public static void main(String[] args) {
List<String> list = Arrays.asList("one", "two", "three", "seven", "nine");
AtomicBoolean yes = new AtomicBoolean(true);
list.stream().takeWhile(value -> yes.get()).forEach(value -> {
System.out.println("prior cond" + value);
if (value.equals("two")) {
System.out.println(value);
yes.set(false);
}
});
//System.out.println("Hello World");
}
What about this one:
final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
if (condition.ok()) {
// YOUR CODE to control
condition.stop();
}
});
Where BooleanWrapper is a class you must implement to control the flow.
I would suggest using anyMatch. Example:-
return someObjects.stream().anyMatch(obj ->
some_condition_met;
);
You can refer this post for understanding anyMatch:-
https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/