java 8 method reference to: either `equals` or `equalsIgnoreCase` - java-8

I tried to convert the body of a method boolean exists(String value, boolean isCaseSensitive) :
for(String str : existingNames){
if(isCaseSensitive ? str.equals(name) : str.equalsIgnoreCase(name)){
return true;
}
}
return false;
to a solution that utilises java8 method references:
Predicate<String> equalityPred = isCaseSensitive ?
name::equals :
name::equalsIgnoreCase;
return existingNames.stream().anyMatch(equalityPred);
Then I saw that this way the equality is performed in the opposite direction (e.g. value.equals(str) ).
Is there a way to fix this and still use method references, and if no what would be the java8 way.

There is no “opposite direction” for equality. The only issue might be the behavior for null values. Your loop might fail, if the collection contains null, your method references will fail, if name is null.
You may achieve the original behavior using lambda expressions:
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
Predicate<String> equalityPred = isCaseSensitive?
s -> s.equals(name):
s -> s.equalsIgnoreCase(name);
return existingNames.stream().anyMatch(equalityPred);
}
but it makes little sense to consider null for the name parameter, when it will never be equal, as the code will fail with a NullPointerException, if the collection contains null.
To get a sensible behavior for null, you may use
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
Predicate<String> equalityPred = name==null? Objects::isNull:
isCaseSensitive? name::equals: name::equalsIgnoreCase;
return existingNames.stream().anyMatch(equalityPred);
}
or just
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
return name==null || isCaseSensitive?
existingNames.contains(name):
existingNames.stream().anyMatch(name::equalsIgnoreCase);
}
If you know that the Collection will never contain null, but want to support null for the name parameter, you could also use
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
return name!=null && existingNames.stream()
.anyMatch(isCaseSensitive? name::equals: name::equalsIgnoreCase);
}

Well don't use a method reference then and write your lambda directly:
static boolean existsJDK8(List<String> existingNames, String value, boolean isCaseSensitive) {
Predicate<String> equalityPred = isCaseSensitive ? s -> value.equals(s) : s -> value.equalsIgnoreCase(s);
Predicate<String> equalityPredReversed = isCaseSensitive ? s -> s.equals(value) : s -> s.equalsIgnoreCase(value);
// return existingNames.stream().anyMatch(equalityPredReversed);
return existingNames.stream().anyMatch(equalityPred);
}

Related

Spring Data JPA - #Query with null values based on user input

The user has a form:
checkbox with fields status and priority
submit btn
Objective: Query DB based on these values.
If one of them is null or false, the criteria should be ignored.
Ex: status is checked and priority is not, I want to query only based on status.
The code below will never execute with one of them being false. I also read about Query by Example but could not find a solution.
Null values can indeed be ignored, but need to be previously defined.
I thought about replacing null with something similar to *.
Ex: WHERE c.status = *. It didn't work.
#Query(value = "SELECT * FROM tickets c WHERE c.status = :status AND c.priority= :priority",
nativeQuery = true)
List<Ticket> findByFilter(#Param("status") String status,
#Param("priority") String priority);
Do you have any idea how can I do this?
Thank you
Thank you Simon for pointing me in the right direction.
This was the web page that helped me:
https://dimitr.im/writing-dynamic-queries-with-spring-data-jpa
My situation:
Created a specification class:
public final class DbFilterSpecification {
public static Specification<Ticket> statusContains(String expression) {
return (root, query, builder) -> builder.like(root.get("status"), contains(expression));
}
public static Specification<Ticket> priorityContains(String expression) {
return (root, query, builder) -> builder.like(root.get("priority"), contains(expression));
}
private static String contains(String expression) {
return MessageFormat.format("%{0}%", expression);
}
}
Created a method inside the service layer:
public List<Ticket> findAllWithSpecification(String status, String priority) {
Specification<Ticket> specification = Specification
.where(status == null ? null : DbFilterSpecification.statusContains(status))
.and(priority == null ? null : DbFilterSpecification.priorityContains(priority));
return ticketRepository.findAll(specification);
}

Use Method that returns an Int inside a Stream

I have a simple method :
public int getPrice(String bookingName)
{
//return the price of a booking
}
I also have the class :
public class Booking
{
String name;
...
}
I want to group the bookings in a map(key = name of the booking, value = getPrice(bookingName)) so I did :
public TreeMap<String, Integer> bookingForName() {
return bookings.stream().
collect(Collectors.groupingBy(Booking::getName,Collectors.summingInt(getPrice(Booking::getName))));
}
This doesnt' work it says :
Multiple markers at this line:
- The target type of this expression must be a functional interface
- The method getPrice(String) in the type Manager is not applicable for the arguments `(Booking::getName)`
How can I do?
Thanks!
Your getPrice() method takes a String, not a functional interface, so you can't call getPrice(Booking::getName), and even if you could, summingInt doesn't accept an int.
Change:
Collectors.summingInt(getPrice(Booking::getName))
to:
Collectors.summingInt(b -> getPrice(b.getName()))
Also note that Collectors.groupingBy returns a Map, not a TreeMap. If you must have a TreeMap, you should call a different variant of groupingBy.
public TreeMap<String, Integer> bookingForName() {
return bookings.stream()
.collect(Collectors.groupingBy(Booking::getName,
TreeMap::new,
Collectors.summingInt(b -> getPrice(b.getName()))));
}

How can I use Optional to return empty if there is any exception in the code in it?

Pretty new to Optional/Java8 usage and I had a doubt regarding its usage.
I have a function in my API which returns a String which can be null or empty. Its similar to finding the id in email like: abc#gmail.com -> abc is o/p.
Now one way of doing this was:
public Optional<String> getUser(final String emailId) {
if (TextUtils.isEmpty(emailId)) {
return Optional.empty();
}
String userIDSeparator = "#";
int userNameEndIndex = emailId.indexOf(userIDSeparator);
if (userNameEndIndex == -1) {
return Optional.empty();
}
return Optional.of(emailId.substring(0, userNameEndIndex));
}
I was wondering if there is any neater way of doing this to return an Optional?
Also, Optional was introduced in Java8 so is there anyway the code can be java7 compatible? I am aware of preprocessors in C not sure if something similar is available.
Note:
I have not compiled this code, so there might be some errors. I wanted the input on Optional.
Thanks!
Well, the code can certainly be reduced. i.e.
public Optional<String> getUser(final String emailId) {
return Optional.of(emailId)
.filter(email -> email.contains("#"))
.map(email -> email.substring(0, email.indexOf("#")));
}
if this method can ever receive a null value then you'd need to change Optional.of(emailId) to Optional.ofNullable(emailId).
As for:
Also, Optional was introduced in Java8 so is there any way the code can
be java7 compatible?
Not that I know of. There may be other libraries that have similar functionality to Java's Optional type, so a little bit of research online may get you to the right place.
Maybe you mean something like this :
public Optional<String> getUser(final String emailId) {
return Optional.ofNullable(emailId)
.filter(email -> email.contains("#"))
.map(email -> Optional.of(email.replaceAll("(.*?)#.*", "$1")))
.orElseGet(Optional::empty);
}
Example
null -> Optional.empty
"" -> Optional.empty
"abc#gmail.com" -> abd
As #Aominè mention, there are some unnecessary parts in my solution, you can use this version instead :
public Optional<String> getUser(final String emailId) {
return Optional.ofNullable(emailId)
.filter(email -> email.contains("#"))
.map(email -> email.replaceAll("(.*?)#.*", "$1"));
}

LINQ Statement dictionary first key's value

I have a dictionary
private Dictionary<string, string> ScannerMessages;
and then I have a call for this
public bool equalMessages()
{
lock (lockObj)
{
return (ScannerMessages.Values.ToList().Distinct().Count() < ScannerMessages.Values.ToList().Count) ? true : false;
}
}
And it returns if the messages are equal. I also need to add to the end of that clause a second check to verify that the values are not null or empty. I was trying to do something like this but I am not sure where to go with the LINQ statement (not the greatest at LINQ)...
public bool equalMessages()
{
lock (lockObj)
{
return ((ScannerMessages.Values.ToList().Distinct().Count() < ScannerMessages.Values.ToList().Count) && (ScannerMessages.Keys.First() *get the value here and check it !null or string.empty) ? true : false;
}
}
To verify all the values are not null or empty:
ScannerMessages.Values.All(s => !string.IsNullOrEmpty(s))
It will return true if all values are not null and not empty.
If you want to get the non-null values you can do this:
ScannerMessages.Values.Where(v=>!string.IsNullOrEmpty(v)).ToList()
or just to get the count
ScannerMessages.Values.Where(v=>!string.IsNullOrEmpty(v)).Count()
or
ScannerMessages[ScannerMessages.Keys.First()].Where(v=>!string.IsNullOrEmpty(v)).Count()

How to extend LINQ select method in my own way

The following statement works fine if the source is not null:
Filters.Selection
.Select(o => new GetInputItem() { ItemID = o.ItemId })
It bombs if "Filters.Selection" is null (obviously). Is there any possible way to write my own extension method which returns null if the source is null or else execute the "Select" func, if the source is not null.
Say, something like the following:
var s = Filters.Selection
.MyOwnSelect(o => new GetInputItem() { ItemID = o.ItemId })
"s" would be null if "Filters.Selection" is null, or else, "s" would contain the evaluated "func" using LINQ Select.
This is only to learn more about LINQ extensions/customizations.
thanks.
You could do this:
public static IEnumerable<U> SelectOrNull<T,U>(this IEnumerable<T> seq, Func<T,U> map)
{
if (seq == null)
return Enumerable.Empty<U>(); // Or return null, though this will play nicely with other operations
return seq.Select(map);
}
Yes have a look at the Enumerable and Queryable classes in the framework, they implement the standard query operators.
You would need to implement a similar class with the same Select extension methods matching the same signatures, then if the source is null exit early, you should return an empty sequence.
Assuming you're talking about LINQ to Objects, absolutely:
public static class NullSafeLinq
{
public static IEnumerable<TResult> NullSafeSelect<TSource, TResult>
(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
// We don't intend to be safe against null projections...
if (selector == null)
{
throw new ArgumentNullException("selector");
}
return source == null ? null : source.Select(selector);
}
}
You may also want to read my Edulinq blog post series to learn more about how LINQ to Objects works.

Resources