How to replace "!= null" statement with method reference? - java

My Intelij shows me that I can replace the lambda .filter(bean -> bean != null) with a method reference. Its is obviuos for me how to do it when I have a Class or an Object with methods. But how to do a reference on != null, is there a Class that has some kind of isNull() method?

This is the exact reason why the Objects::nonNull API exists:
.filter(Objects::nonNull);

Moved from comment to answer
Of course, as Aomine says, you can use Objects::nonNull for this.
But for code that doesn't have an available function, I think it's useful to know that you can use a lot of things in lambda expressions; You can use code blocks or just write a simple method following the contract of the lambda and passing a reference to that method.
class Test {
public static void main(String[] args){
Stream<Object> stream = ...;
// lambda from code block
stream.filter(bean -> {return bean != null;});
Predicate<Object> p1 = o -> {return o != null;};
// which resolves to the below
Predicate<Object> p2 = new Predicate<>() {
#Override public boolean test(Object o) {
return o != null;
}
};
// or pass your own method that can resolve to the correct functional class
stream.filter(Test::myPredicateTest);
}
// meets the contract of a Predicate<Object>.test(Object o) returning boolean
public static boolean myPredicateTest(Object o) {
return o != null;
}
}

Yes, of course; you can use the Objects::nonNull API.
package com.logicbig.example.objects;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class NonNullExample {
public static void main(String... args) {
List<String> list = Arrays.asList(null, null, "first_element", "second_element", null);
list = list.stream().filter(Objects::nonNull).collect(Collectors.toList());
System.out.println(list);
}
}

Related

How to use lambda and predicate for example if you disagree with the java.net.URI implementation?

My goal is to override the isAbsolute method from the java.net.URI to follow the RFC3986 about absolute-uri which invalidate a uri if it have fragment. Unfortunately, I can not extends the class.
Someone at SO recommended me to use Predicate and String. Unfortunately, he deleted his answer. So, I am sort of being creative right now.
import java.net.URI;
import java.net.URISyntaxException;
import java.util.function.Predicate;
public class PredicateAsParameter {
public static void main(String[] args) throws URISyntaxException {
URI uri = new URI("http://www.example.com/#fragment");
boolean isAbsolute1val = isAbsolute1met(uri);
System.out.println(isAbsolute1val);
boolean isAbsolute2val = isAbsolute2met(uri, (x) -> x.getScheme() != null && x.getAuthority() != null && x.getFragment() == null);
System.out.println(isAbsolute2val);
}
public static Boolean isAbsolute1met(URI uri) {
return uri.getScheme() != null && uri.getAuthority() != null && uri.getFragment() == null;
}
public static Boolean isAbsolute2met(URI uri, Predicate<URI> condition) {
return condition.test(uri);
}
}
My expected result is that I can use the Predicate, somehow find new way to write code.
My actual result is that I have not figured out why to use Predicate. I feel a bit off and somehow feel that I am testing against the Object instead of against the attributes of the Object by using the Predicate and Lambda. So, I feel, that I am using it wrong.

Generic Method with Document and BasicDBObject in Java

I'm learning generics and trying to write generic method in a project that I'm working on. I have a use case where I have a method which is recursive, which is exactly same but the parameters type are either Document or BasicDBObject. These parameters have nested list of objects so each of them again have objects of type Document or BasicDBObject inside them. So I have overloaded the methods with both the types. Can I use generics to change this method to accept any type?
public <T> String convertToRules(T rulesObj) {
final StringBuilder expressionBuilder = new StringBuilder("${");
if (rulesObj.getString("condition") != null) {
String condition = rulesObj.getString("condition");
if (rulesObj.get("rules") != null) {
ArrayList<BasicDBObject> rules = (ArrayList<BasicDBObject>) rulesObj.get("rules");
// rules can be ArrayList<BasicDBObject> or ArrayList<Document> so just mentioning them
// both here in question to avoid confusion of what type they are.
ArrayList<Document> rules = (ArrayList<Document>) rulesObj.get("rules");
rules.forEach(rule -> {
// Some code
expressionBuilder.append(convertToRules(rule));
}
}
}
There are compiler errors in the above code as I was trying to convert the existing method to generic method. Below are the actual methods.
public String convertToRules(BasicDBObject rulesObj) {
final StringBuilder expressionBuilder = new StringBuilder("${");
if (rulesObj.getString("condition") != null) {
String condition = rulesObj.getString("condition");
if (rulesObj.get("rules") != null) {
ArrayList<BasicDBObject> rules = (ArrayList<BasicDBObject>) rulesObj.get("rules");
rules.forEach(rule -> {
// Some code
expressionBuilder.append(convertToRules(rule));
}
}
}
public String convertToRules(Document rulesObj) {
final StringBuilder expressionBuilder = new StringBuilder("${");
if (rulesObj.getString("condition") != null) {
String condition = rulesObj.getString("condition");
if (rulesObj.get("rules") != null) {
ArrayList<Document> rules = (ArrayList<Document>) rulesObj.get("rules");
rules.forEach(rule -> {
// Some code
expressionBuilder.append(convertToRules(rule));
}
}
}
I'm pretty sure this is not the right way to do it, need some guidance on how this can be achieved. I want to know if I'm thinking the right way about generics or this implementation is wrong.
RuleType - Contract of Two objects.
import java.util.List;
public interface RuleType<T> {
String getString(String parameter);
List<T> get(String param);
}
BasicDBObject
import java.util.ArrayList;
import java.util.List;
public class BasicDBObject implements RuleType<BasicDBObject> {
#Override
public String getString(String parameter) {
return "Something";
}
#Override
public List<BasicDBObject> get(String param) {
return new ArrayList<>();
}
}
Doument
import java.util.ArrayList;
import java.util.List;
public class Document implements RuleType<Document> {
#Override
public String getString(String parameter) {
return "Something";
}
#Override
public List<Document> get(String param) {
return new ArrayList<>();
}
}
Generic Method (Logic implementation)
public <T extends RuleType> String convertToRules(T rulesObj) {
final StringBuilder expressionBuilder = new StringBuilder("${");
if (rulesObj.getString("condition") != null) {
String condition = rulesObj.getString("condition");
if (rulesObj.get("rules") != null) {
List<T> rules = rulesObj.get("rules");
rules.forEach(rule ->
// Some code
expressionBuilder.append(convertToRules(rule))
);
}
}
return expressionBuilder.toString();
}
You can make an abstract superclass or interface for both of the class. Let's say SuperClass with the common methods like getString() of the BasicDBObject and Document. Then, override the methods in the two class. Then for the generic method, you can make it like <? extends SuperClass. Then you can read the property of SuperClass easily. I think it should work fine.

Compare 2 objects ignoring null values

The project uses TestNg, Java11, Spring test
I am writing testNG tests for API
I have a java object that has this kind of stucture:
class Object1
private Object2 o2;
private List<Object3> o3;
Where Object2 is not only composed of primitive attributes.
I would like to test if 2 Object1 are equals with these rules:
if actual o2 is null, don't fail even if the other o2 is not
if actual o3 is null or empty, don't fail even if the other o3 is not
if actual o3 is not null nor empty, compare only non null Object3 fields
To sum up, I would like to assert that 2 objects are the same, ignoring null fields recursively.
I could do it
assertThat(actual).usingRecursiveComparison().ignoringActualNullFields().isEqualTo(other);
but the recursive null fields are not ignored.
How can I fix this?
You can also ignore expected null fields..
Can you also provide a simple test to reproduce the issue?
Feel free to raise an issue in https://github.com/joel-costigliola/assertj-core/issues
For me following code worked:
public class SocialLink {
private String platform;
private String link;
}
SocialLink obj1 = new SocialLink("Facebook", null);
SocialLink obj2 = new SocialLink("Facebook", null);
assertThat(obj1).isEqualToIgnoringNullFields(obj2);
I finally created my own asserts like this:
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import java.util.List;
import java.util.stream.Collectors;
public class Object1Assert extends AbstractAssert<Object1Assert, Object1> {
public Object1Assert isEqualTo(Object1 other) {
// specially for null
if(actual == other) {return this;}
if(actual.getObject2() != null) {
Assertions.assertThat(other.getObject2()).isEqualToIgnoringNullFields(actual.getObject2());
}
if(actual.getObject3() != null) {
for(Object3 object3 : actual.getObject3()) {
my.package.Assertions.assertThat(object3).isIn(other.getObject3());
}
}
// return the current assertion for method chaining
return this;
}
public Object1Assert(Object1 actual) {
super(actual, Object1Assert.class);
}
public static Object1Assert assertThat(Object1 actual) {
return new Object1Assert(actual);
}
}
public class Assertions {
public static Object3Assert assertThat(Object3 actual) {
return new Object3Assert(actual);
}
}
public class Object3Assert extends AbstractAssert<Object3Assert, Object3> {
public Object3Assert isIn(List<Object3> others) {
List<String> otherStringIds = others.stream().map(Object3::getStringId).collect(Collectors.toList());
Assertions.assertThat(otherStringIds).isNotEmpty();
Assertions.assertThat(actual.getStringId()).isIn(otherStringIds);
for (Object3 otherObject3 : others) {
if(actual.getStringId().equalsIgnoreCase(otherObject3.getStringId())) {
Assertions.assertThat(otherObject3).usingComparatorForType(Comparators.bigDecimalComparator, BigDecimal.class).isEqualToIgnoringNullFields(actual);
}
}
// return the current assertion for method chaining
return this;
}
public Object3Assert(Object3 actual) {
super(actual, Object3Assert.class);
}
public static Object3Assert assertThat(Object3 actual) {
return new Object3Assert(actual);
}
}
I created this class for each type I needed with this tutorial
https://www.baeldung.com/assertj-custom-assertion

(Predicate<? super String> s) or (String s)

I have a TreeSet of Strings (hardcoded).
Want to check that a given parameter String eg. "Person" if present in the TreeSet then return true otherwise return false.
Here I am confused by the Eclipse message regarding
(Predicate<? super String> s) vs (String s):
The method anyMatch(Predicate) in the type Stream is not applicable for the arguments (String)
Please guide.
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Predicate;
public class SystemLabelValidator {
public static boolean ValidateSystemLabel( String s) {
String j = s;
boolean b = false;
Set <String> SystemLabels = new TreeSet<String>();
// Unique Strings
SystemLabels.add("Person");
SystemLabels.add("Player");
SystemLabels.add("Hospital");
SystemLabels.add("Nurse");
SystemLabels.add("Room");
System.out.println("\n==> Loop here.");
for (String temp : SystemLabels) {
System.out.println(temp);
if(SystemLabels.stream().anyMatch(j)) {
System.out.println("I need to return Boolean");
}
return b;
}
return b;
}
}
There is no need to use a Predicate here. In order to check if the String is present in your TreeSet just use :
return systemLabels.contains("Person");
If you still insist on using anyMatch then you can do :
public static boolean validateSystemLabel(String s) {
return systemLabels.stream().anyMatch(i -> i.equals(s));
}
Remember, a predicate expression needs to evaluate to a boolean value but in the code, you are passing in a String hence the compilation error.
The problem in your solution is this line:
SystemLabels.stream().anyMatch(j);
Basically anyMatch() expects Predicate as input not String.
But your problem has simpler solution:
import java.util.Set;
import java.util.TreeSet;
public class SystemLabelValidator {
private static final Set<String> SYSTEM_LABLES = new TreeSet<>(Arrays.asList("Person", "Player", "Hospital", "Nurse", "Room"));
public static boolean validateSystemLabel( String value) {
return SYSTEM_LABLES.contains(value);
}
}
The signature of anyMatch is
boolean anyMatch(Predicate<? super T> predicate)
In your case, the argument must be a Predicate<? super String>. That is, a method which can take a string and return a boolean. This method is looking for one of the following
Predicate<String> (e.g. String::isEmpty)
Predicate<Object> (e.g. Objects::isNull)
Predicate<CharSequence>
Predicate<Comparable<String>>
Predicate<Serializable>
You have attempted to give it a string, which does not match the signature. One way to fix this would be:
if(SystemLabels.stream().anyMatch(j::equals)) {
System.out.println("I need to return Boolean");
}

method returning either a collection or a single value

I have a class with various properties and I would like to write a wrapper method around them in order to loop around them more easily.
Some properties return a collection of values, some a single value. And I'm looking for the best approach for this.
My first approach is to let the wrapper method return whatever the property getters return.
public class Test {
public Object getValue(String propName) {
if ("attr1".equals(propName)) return getAttribute1();
else if ("attr2".equals(propName)) return getAttribute2();
else return null;
}
public List<String> getAttribute1() {
return Arrays.asList("Hello","World");
}
public String getAttribute2() {
return "Goodbye";
}
public static void main(String[] args) {
final Test test=new Test();
Stream.of("attr1","attr2")
.forEach(p-> {
Object o=test.getValue(p);
if (o instanceof Collection) {
((Collection) o).forEach(v->System.out.println(v));
}
else {
System.out.println(o);
}
});
}
}
The bad point with this approach is that the caller has to test himself whether the result is a collection or not.
Other approach, seamless for the caller, is to always return a collection, ie. the wrapper function wraps the single values into a Collection. Here an HashSet, but we can imagine an adhoc, minimum 1 element list.
public class TestAlt {
public Collection getValue(String propName) {
if ("attr1".equals(propName))
return getAttribute1();
else if ("attr2".equals(propName)) {
Set s = new HashSet();
s.add(getAttribute2());
return s;
}
else
return null;
}
public List<String> getAttribute1() {
return Arrays.asList("Hello", "World");
}
public String getAttribute2() {
return "Goodbye";
}
public static void main(String[] args) {
final TestAlt test = new TestAlt();
Stream.of("attr1", "attr2")
.forEach(p -> {
test.getValue(p).forEach(v -> System.out.println(v));
});
}
Performance-wise, design-wise, ... what's your opinion on these approaches ? Do you have better ideas ?
Well, you could pass the action to be performed on each attribute to the object and let the object decide on how to handle it. E.g.:
in Class Test:
public void forEachAttribute(String propName, Handler h) {
if ("attr1".equals(propName))
h.handle(getAttribute1());
else if ("attr2".equals(propName)) {
getAttribute2().forEach(o -> h.handle(o))
}
}
And a class Handler with the function handle(String s), that does, what you want to do.
If you cannot edit Test, you can also move the function outside Test
public void forEachTestAttribute(Test t, String propName, Handler h)...
Performance-wise: This removes an if-clause
Design-wise: This removes a cast, but creates more classes.
*Edit: It also maintains type-security, and if there are multiple kinds of attributes (String, int, etc.) you could add more handle-functions, to still maintain type-security.
Regarding the design I would rewrite your code into this:
TestAlt.java
import java.util.*;
import java.util.stream.Stream;
public class TestAlt {
private Map<String, AttributeProcessor> map = AttributeMapFactory.createMap();
public Collection getValue(String propName) {
return Optional
.ofNullable(map.get(propName))
.map(AttributeProcessor::getAttribute)
.orElse(Arrays.asList("default")); //to avoid unexpected NPE's
}
public static void main(String[] args) {
final TestAlt test = new TestAlt();
Stream.of("attr1", "attr2")
.forEach(p -> test.getValue(p).forEach(v -> System.out.println(v)));
}
}
AttributeMapFactory.java
import java.util.HashMap;
import java.util.Map;
public class AttributeMapFactory {
public static Map<String, AttributeProcessor> createMap() {
Map<String, AttributeProcessor> map = new HashMap<>();
map.put("attr1", new HiAttributeProcessor());
map.put("attr2", new ByeAttributeProcessor());
return map;
}
}
AttributeProcessor.java
import java.util.Collection;
public interface AttributeProcessor {
Collection<String> getAttribute();
}
HiAttributeProcessor.java
import java.util.Arrays;
import java.util.Collection;
public class HiAttributeProcessor implements AttributeProcessor{
#Override
public Collection<String> getAttribute() {
return Arrays.asList("Hello", "World");
}
}
ByeAttributeProcessor.java
import java.util.Arrays;
import java.util.Collection;
public class ByeAttributeProcessor implements AttributeProcessor{
#Override
public Collection<String> getAttribute() {
return Arrays.asList("Goodbye");
}
}
The main point is that you get rid of if-else statements using map and dynamic dispatch.
The main advantage of this approach is that your code becomes more flexible to further changes. In case of this small programm it does not really matter and is an overkill. But if we are talking about large enterprise application, then yes, it becomes crucial.

Categories