First I need to check if data is present in list then get else set default or empty value on a Java 8 stream.
Currently I am using below code without isPresent but I dont know how to use isPresent in java8.
I am trying something below which is not perfect:
String isScheme = (this.mapProgramApproaches.stream().findFirst().isPresent())? this.mapProgramApproaches.stream().findFirst().get().getIsScheme().toString() : "0";
Where as mapProgramApproaches this is set.
Don't use isPresent() (it makes no sense to run the Stream pipeline twice).
You can use map to map the value of the Optional to the required String, and then
use orElse() to return a default value when the Optional value is not present:
String isScheme = this.mapProgramApproaches.stream()
.findFirst()
.map(o->o.getIsScheme().toString())
.orElse("0");
Maybe you are looking for something like this:
String isScheme = this.mapProgramApproaches.stream()
.findFirst()
.map(p -> p.getIsScheme().toString())
.orElse("0");
I'm not sure about context in which you are doing this, but I suppose that you would like to check whether some object is scheme and then do something with that. In that case I would suggest implement it like this:
List<String> mapProgramApproaches = new ArrayList<>();
mapProgramApproaches.stream()
.filter(this::isScheme)
.findFirst()
.ifPresent(this::doYourCode)
.orElse(defaultValue);
It will make your code cleaner. And will help to avoid additional conditionals!
Related
Is there any way to use both FailableFunction and Function lambdas into a single .map chaining stream?
Function<String, Organization> hook = (id) -> this.organizationRepository.findById(id).get();
FailableFunction<Organization, Organization, MpiException> failableSave = (r) -> this.organizationRepository.save(r);
List<String> ids;
Failable.stream(ids)
.map(hook)
.map(failableSave)
.collect(Collectors.toList());
I'm getting:
The method map(FailableFunction<String,R,?>) in the type Streams.FailableStream is not applicable for the arguments (Function<String,Organization>)
Problem here is that sometimes I need to use Function and other times I need to use FailableFunction.
Any ideas about how to use them into same stream mapping chaining?
Maybe not the most elegant solution, but since nobody else came up with something:
You could use a method reference to implicitly convert a Function into a FailableFunction:
Failable.stream(ids)
.map(hook::apply)
.map(failableSave)
.collect(Collectors.toList());
I want to use Optional for handling null values, the "tricky" part which I cannot think of what is the best way to do - is that I want to do logging if value is null. I can achieve that with following code - but it feels awkward.
(Update: I have posted my own answer, with Optional from Java 9)
Lets say code looks like this:
// logLine.getSomeProperty returns Optional<String>
List<LogDetails> logDetails = logLine.getSomeProperty()
.map(this::extractLogDetails)
.orElseGet(() -> logError(logLine));
List<LogDetails> extractLogDetails(String s) {
List<LogDetails> logDetails = new ArrayList<>();
String sp = "(?:([A-Z0-9]{5,7})-([A-Z0-9]{9})-(.{4}))";
Pattern p = Pattern.compile(sp, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(s);
while (m.find()) {
logDetails.add(new LogDetails(m.group(1), m.group(2), m.group(3)));
}
return logDetails;
}
List<LogDetails> logError(LogLine logLine) {
log.error("Error while ... {} ", logLine));
persistence.setErrorStatus(logLine, FAILED_PARSING);
return new ArrayList<>();
}
It would do what I want, but I have several "problems" with it.
I found it odd, that method called orElseGet is used for logging
errors.
I could replace orElseGet with orElseThrow and logError there and DO NOT throw anything - which I don't like either.
logError method returns List which I don't use and it looks weird to return something from method which should be void.
Simply there must be better way
Cases where someProperty is not null, but there are no matches - I would like to log as well, but for that I would need another line of code to check if logDetails.size() == 0
The orElseGet is not really intended as an error handling mechanism, but as a way to generate a different default value in case the Optional instance is not carrying any.
If you want to check if the Optional is empty explicitly, simply use the Optional.isPresent() check, and do the logError() in that case.
What you need to think first is, if the Optional is empty, what do you want to do? Apart from logging the error, do you want to proceed with an empty list?
If yes then you could have something like this:
List<LogDetails> logDetails = logLine.getSomeProperty()
.map(this::extractLogDetails)
.orElseGet(Collections::emptyList);
After which you could do:
if (logDetails.isEmpty()) {
logError(logline);
}
Alternatively, if you do not want to have an empty list at all, you could keep things at optional level. This way, both cases where the getSomeProperty() is empty or when the generated list is empty are handled in the same way.
Optional<List<LogDetails>> logDetailsOpt = logLine.getSomeProperty()
.map(this::extractLogDetails)
.filter(list -> !list.isEmpty());
if (!logDetailsOpt.isPresent()) {
logError(logLine);
}
In both cases, logError() is not expected to return anything. It is doing what it is intended to do in its name, logging the error.
Rather than trying to overuse the functionality of Optional, try to make your intentions in your code clear. There is more value in readability.
Rather than changing result type or logging inside stream you can simply return partitioned Map. Then after obtaining the result, execute log function on the resulting map accordingly.
Map<Boolean, List<String>> map = Stream.of("a", "aaa", "aaaa")
----
.collect(() -> Collectors.partitioningBy(predicate))
----
While I am grateful for the answers, but I just recently find out, that Java 9 introduced new method to Optional and I like it best.
Here is example.
Optional.ofNullable(user).ifPresentOrElse( u -> logger.info("User is:" + u.getEmail()),
() -> logger.info("User not found"));
I have some data stored in a JPA Repository that I am trying to process. I would like to be able to use Java 8 Streams to do so, but can not figure out how to get the required information. This particular 'Entity' is actually only for recovery, so it holds items that would need to be processed after something like a power-fail/restart.
Using pre-Java 8 for-loops the code would look like:
List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
for (MyEntity item : deletes) {
String itemJson = item.getData();
// use a Jackson 'objectMapper' already setup to de-serialize
MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
processDelete(deleteEvent, item.getId());
}
The problem arises from the two parameter method called at the very end. Using Streams, I believe I would do:
// deletes.stream()
// .map(i -> i.getData())
// .map(event -> objectMapper.readValue(event, MyEventClass.class))
// .forEach(??? can't get 'id' here to invoke 2 parameter method);
I have a solution (without Streams) that I can live with. However I would think this problem comes up a lot, thus my question is: IN GENERAL, is there a way using Streams to accomplish what I am trying to do?
Why not a Pair return on your map operation:
.map(i -> new Pair<>(i.getData(), i.getId()))
.map(pair -> new Pair<>(objectMapper.readValue(pair.getLeft(), MyEventClass.class), pair.getRight())
.forEach(p -> processDelete(pair.getLeft(), pair.getRight()))
I did not compile this, so there might be minor things to fix. But in general, you would need a Holder to pass your objects to the next stage in such a case. Either a Pair or some type or even a array.
Why not doing it simply this way?
deletes.forEach(item ->
processDelete(objectMapper.readValue(item.getData(), MyEventClass.class),
item.getId()));
This is a start at least, I guess it is dependent on why you want to use stream and how much you want to make it more functional
List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
deletes.stream().foreach(item -> {
String itemJson = item.getData();
// use a Jackson 'objectMapper' already setup to de-serialize
MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
processDelete(deleteEvent, item.getId());
});
I am pretty new to streams.
I would like to stream the geometries EC_Geometry arraylist and if the EC_Geometry element is not present (or better equals never returns true), then I add it.
public void init(GL3 gl3, EC_Mesh mesh) {
geometries.stream()
.filter(geometry -> mesh.getGeometry().equals(geometry))
.findAny()
.orElse(..?);
}
But I am stuck at the last line
How can I solve it using streams?
Please note that equals is a method I wrote checking if the geometry is the same (i.e: if the triangles correspond)
orElse will always run even if the value returned isn't used so it is preferable to use orElseGet here which will only run if nothing is found.
geometries.stream()
.filter(geometry -> mesh.getGeometry().equals(geometry))
.findAny()
.orElseGet(() -> {
geometries.add(mesh.getGeometry());
return mesh.getGeometry();
});
.findAny().orElse(..?);
is for Optional - if you would like to get first element found.
For what you would like to achieve the best approach would be just to:
meshG = mesh.getGeometry();
if (!geometries.contains(meshG)) {
geometries.add(meshG);
}
No need to overuse Stream API.
I want to prepend a stream with an Optional. Since Stream.concat can only concatinate Streams I have this question:
How do I convert an Optional<T> into a Stream<T>?
Example:
Optional<String> optional = Optional.of("Hello");
Stream<String> texts = optional.stream(); // not working
If restricted with Java-8, you can do this:
Stream<String> texts = optional.map(Stream::of).orElseGet(Stream::empty);
In Java-9 the missing stream() method is added, so this code works:
Stream<String> texts = optional.stream();
See JDK-8050820. Download Java-9 here.
You can do:
Stream<String> texts = optional.isPresent() ? Stream.of(optional.get()) : Stream.empty();
I can recommend Guava's Streams.stream(optional) method if you are not on Java 9. A simple example:
Streams.stream(Optional.of("Hello"))
Also possible to static import Streams.stream, so you can just write
stream(Optional.of("Hello"))
If you're on an older version of Java (lookin' at you, Android) and are using the aNNiMON Lightweight Stream API, you can do something along the lines of the following:
final List<String> flintstones = new ArrayList<String>(){{
add("Fred");
add("Wilma");
add("Pebbles");
}};
final List<String> another = Optional.ofNullable(flintstones)
.map(Stream::of)
.orElseGet(Stream::empty)
.toList();
This example just makes a copy of the list.
It can depend of how you want to convert empty optional to stream element.
If you want to interpret it as "nothing" (or "no element"):
Stream<String> texts = optional.stream(); // since JDK 9
Stream<String> texts = optional.map(Stream::of).orElseGet(Stream::empty); // JDK 8
But if you want to interpret it as null:
Stream<String> texts = Stream.of(optional.oreElse(null));
A nice library from one of my ex collegues is Streamify. A lot of collectors, creating streams from practicly everything.
https://github.com/sourcy/streamify
Creating a stream form an optional in streamify:
Streamify.stream(optional)