Consider the following class
Class RequestBodyResource {
private RequestVariable1 att1;
private String att2;
private String att3;
}
I have a method that should return false in 2 conditions
If all the 3 attributes of the RequestBodyResource Object is null/empty
If more than one attribute is not null
Basically "at least one" OR "at most one"
The code for the same is as
public boolean validateExactlyOneRequiredRequestParam(RequestBodyResource request) {
//The below 3 conditions are to test that only one request is present
if(StringUtils.isNotEmpty(request.getAtt3()) && null != request.getAtt1()) {
return false;
}
if(StringUtils.isNotEmpty(request.getAtt2()) && null != request.getAtt1()) {
return false;
}
if(StringUtils.isNotEmpty(request.getAtt3()) && StringUtils.isNotEmpty(request.getAtt2())) {
return false;
}
//The below condition is to test that at least one request is present
if(StringUtils.isEmpty(request.getAtt3()) && null == request.getAtt1() && StringUtils.isEmpty(request.getAtt2())) {
return false;
}
return true;
}
How to use Java 8 Optional to make this code much easier to write and read?
Why not just count?
int count = 0;
if(request.getAtt1() !=null) {
count++;
}
if(StringUtils.isNotEmpty(request.getAtt2())) {
count++;
}
if(StringUtils.isNotEmpty(request.getAtt3())) {
count++;
}
return count == 1;
Version with Optional (do not use, it is added just for fun).
return Optional.ofNullable(request.getAtt1()).map(ignore -> 1).orElse(0)
+ Optional.ofNullable(request.getAtt2()).map(ignore -> 1).orElse(0)
+ Optional.ofNullable(request.getAtt3()).map(ignore -> 1).orElse(0)
== 1;
Also it lack of check of empty strings.
There is no need for an Optional here as such. If you just need to check if at least one of those attributes are present, you could simply check it as:
public boolean validateAtLeastOneRequiredRequestParam(RequestBodyResource request) {
return request.getAtt1() != null
|| !StringUtils.isEmpty(request.getAtt3())
|| !StringUtils.isEmpty(request.getAtt2());
}
Edit 1: For an exactly one check, not so good yet more readable(IMHO) than your current solution would be:
public boolean validateExactlyOneRequiredRequestParam(RequestBodyResource request) {
long countPresentAttribute = Stream.of(request.getAtt2(), request.getAtt3())
.filter(StringUtils::isNotEmpty)
.count() +
Stream.of(request.getAtt1()).filter(Objects::nonNull).count();
return countPresentAttribute == 1;
}
Edit 2: Using Optional and getting rid of an external dependency on StringUtils, you could do it as :
public boolean validateExactlyOneRequiredRequestParam(RequestBodyResource request) {
long countPresentAttribute = Stream.of(
Optional.ofNullable(request.getAtt1()),
Optional.ofNullable(request.getAtt2()).filter(String::isEmpty),
Optional.ofNullable(request.getAtt3()).filter(String::isEmpty))
.filter(Optional::isPresent)
.count();
return countPresentAttribute == 1;
}
Related
I have two similar methods in terms of the body, but with a different number of parameters and an extra condition inside. I know there is a way of merging them into a single method using a predicate, but I am not entirely sure how to implement it. Which is the best way to approach this?
public boolean checkIfAllCodesAreUnique(List<String> bsnCodes)
{
List<Businesscode> codes = ConverterUtil.iterableToList(businessCodeService.findAll());
if(codes != null && !codes.isEmpty() && bsnCodes != null && !bsnCodes.isEmpty())
for (String code : bsnCodes)
if (codes.stream().anyMatch(obj -> code.equals(obj.getCode())))
return false;
return true;
}
public boolean checkIfAllCodesAreUnique(List<String> bsnCodes, int idRole)
{
List<Businesscode> codes = ConverterUtil.iterableToList(businessCodeService.findAll());
if(codes != null && !codes.isEmpty() && bsnCodes != null && !bsnCodes.isEmpty())
for (String code : bsnCodes)
if (codes.stream().anyMatch(obj -> code.equals(obj.getCode()) && obj.getId() != idRole))
return false;
return true;
}
public boolean checkIfAllCodesAreUnique(List<String> bsnCodes) {
return isAllCodesAreUnique(bsnCodes, businessCode -> true);
}
public boolean checkIfAllCodesAreUnique(List<String> bsnCodes, int idRole) {
return isAllCodesAreUnique(bsnCodes, businessCode -> businessCode.getId() != idRole);
}
private boolean isAllCodesAreUnique(List<String> bsnCodes, Predicate<Businesscode> checkRole) {
List<Businesscode> businessCodes = Optional.ofNullable(ConverterUtil
.iterableToList(businessCodeService.findAll())).orElse(List.of());
for (String bsnCode : Optional.ofNullable(bsnCodes).orElse(List.of())) {
if (businessCodes.stream()
.filter(businessCode -> bsnCode.equals(businessCode.getCode()))
.anyMatch(checkRole))
return false;
}
return true;
}
Basically predicate would not allow you anything specific in the sense of auto-determinable interface or whatever. Probably the best combination of the two would be:
public boolean checkIfAllCodesAreUnique(List<String> bsnCodes, Integer idRole)
{
List<Businesscode> codes = ConverterUtil.iterableToList(businessCodeService.findAll());
if(codes != null && !codes.isEmpty() && bsnCodes != null && !bsnCodes.isEmpty())
for (String code : bsnCodes)
if (codes.stream().anyMatch(obj -> code.equals(obj.getCode()) || (idRole != null && obj.getId() != idRole))
return false;
return true;
}
And then pass the second parameter as null whenever not available.
I want to write a code to check the existence of given two values in a List.
List<Tag> tags = new ArrayList<>();
The requirement is to return true only if the List tag contains both "start" and "end" values.
My code is like this, but it doesn't cater to the requirement.
public static boolean checkStartAndEndTimeTag(List<Tag> tags) {
boolean isSuccess = false;
int count = 0;
for (Tag tag : tags) {
if (tag.getKey().equals("start") || tag.getKey().equals("end")) {
count++;
if (count == 2)
break;
isSuccess = true;
}
}
return isSuccess;
Can someone help me with to resolve this issue?
This...
if (count == 2)
break;
isSuccess = true;
doesn't make sense. This will set isSuccess even if there is only one match
The long winded approach
Okay, let's assuming for a second that you only care if there is at least one start and one end (discounting duplicates). One approach would be to use to state flags, one for start and one for end. To keep it simple, they would start of as 0 but would only ever be a maximum of 1 (because we don't want duplicates), then you might be able to do something like...
public static boolean checkStartAndEndTimeTag(List<Tag> tags) {
boolean isSuccess = false;
int starts = 0;
int ends = 0;
for (Tag tag : tags) {
if (tag.getKey().equals("start")) {
starts = 1;
} else if (tag.getKey().equals("end")) {
ends = 1;
}
}
isSuccess = (starts + ends) == 2;
return isSuccess;
}
Ok, you don't need isSuccess = (starts + ends) == 2; and could simply return the result of the comparison. You could also break out of the loop if (starts + ends) == 2 and save yourself from unnecessary computation
for (Tag tag : tags) {
if (tag.getKey().equals("start")) {
starts = 1;
} else if (tag.getKey().equals("end")) {
ends = 1;
}
if ((starts + ends) == 2) {
break;
}
}
Using streams...
One approach might be to make use the streams support and simply filter the List and count the results, for example...
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
List<Tag> tags = new ArrayList<Tag>(25);
tags.add(new Tag("begin"));
tags.add(new Tag("front"));
tags.add(new Tag("start"));
tags.add(new Tag("finish"));
tags.add(new Tag("tail"));
tags.add(new Tag("end"));
boolean isSuccessful = tags.stream().filter(tag -> tag.getKey().equals("start") || tag.getKey().equals("end")).count() >= 2;
System.out.println(isSuccessful);
}
public class Tag {
private String key;
public Tag(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
}
Updated...
Okay, this got complicated fast. Let's assume you don't want to match two start tags, so you MUST have both one end and one start tag
So, using the above, example, we can modify the Tag class to support equals (and by extension hashcode)
public class Tag {
private String key;
public Tag(String key) {
this.key = key;
}
public String getKey() {
return key;
}
#Override
public String toString() {
return getKey();
}
#Override
public int hashCode() {
int hash = 7;
hash = 73 * hash + Objects.hashCode(this.key);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Tag other = (Tag) obj;
if (!Objects.equals(this.key, other.key)) {
return false;
}
return true;
}
}
Then we can simply use distinct to filter out any duplicates, for example...
boolean isSuccessful = tags
.stream()
.distinct()
.filter(tag -> tag.getKey().equals("start") || tag.getKey().equals("end"))
.count() >= 2;
Probably not the most efficient solution, but certainly one of the shortest
In this code
if (tag.getKey().equals("start") || tag.getKey().equals("end")) {
count++;
if (count == 2)
break;
isSuccess = true;
}
you are setting isSuccess to true whenever the tag is start or end.
Better way would be
if (tag.getKey().equals("start") || tag.getKey().equals("end")) {
count++;
if (count == 2)
return true;
}
You could also use
tags.stream()
.map(Tag::getKey)
.distinct()
.filter(t -> "start".equals(t) || "end".equals(t))
.count() == 2;
This would also fix the issue that your original code falsely returns true if the list contains statt or end twice.
What about
tags.containsAll(Arrays.asList(new Tag("start"), new Tag("stop")))
I have a method which checks for nulls. Is there a way to reduce the number of lines in the method? Currently, the code looks "dirty":
private int similarityCount (String one, String two) {
if (one == null && two == null) {
return 1;
} else if (one == null && two != null) {
return 2;
} else if (one != null && two == null) {
return 3;
} else {
if(isMatch(one, two))
return 4;
return 5;
}
}
private int similarityCount (String one, String two) {
if (one == null && two == null) {
return 1;
}
if (one == null) {
return 2;
}
if (two == null) {
return 3;
}
if (isMatch(one, two)) {
return 4;
}
return 5;
}
I prefer nested conditions in such cases :
private int similarityCount (String one, String two) {
if (one==null) {
if (two==null) {
return 1;
} else {
return 2;
}
} else {
if (two==null) {
return 3;
} else {
return isMatch(one, two) ? 4 : 5;
}
}
}
Of course you can achieve a shorter version by using more ternary conditional operators.
private int similarityCount (String one, String two) {
if (one==null) {
return (two==null) ? 1 : 2;
} else {
return (two==null) ? 3 : isMatch(one, two) ? 4 : 5;
}
}
Or even (now this is getting less readable) :
private int similarityCount (String one, String two) {
return (one==null) ? ((two==null) ? 1 : 2) : ((two==null) ? 3 : isMatch(one, two) ? 4 : 5);
}
Since the actual purpose of the function seems to be to handle non-null objects by matching them, I’d handle all the null checks in a guard statement at the beginning.
Then, once you’ve established that no argument is null, you can handle the actual logic:
private int similarityCount(String a, String b) {
if (a == null || b == null) {
return a == b ? 1 : a == null ? 2 : 3;
}
return isMatch(a, b) ? 4 : 5;
}
This is both more concise and more readable than the other options.
That said, real functions wouldn’t usually return such numeric codes. Unless your method was simplified to exemplify the problem, I’d strongly urge you to reconsider the logic and instead write something akin to what follows:
private boolean similarityCount(String a, String b) {
if (a == null || b == null) {
throw new NullPointerException();
}
return isMatch(a, b);
}
Or:
private boolean similarityCount(String a, String b) {
if (a == null) {
throw new IllegalArgumentException("a");
}
if (b == null) {
throw new IllegalArgumentException("b");
}
return isMatch(a, b);
}
These approaches would be more conventional. On the flip side, they may trigger an exception. We can avoid this by returning a java.util.Optional<Boolean> in Java 8:
private Optional<Boolean> similarityCount(String a, String b) {
if (a == null || b == null) {
return Optional.empty();
}
return Optional.of(isMatch(a, b));
}
At first glance this may seem to be no better than returning null but optionals are in fact far superior.
The code looks clear enough for me. You can make it shorter with nesting and ternary operators:
if(one==null) {
return two==null ? 1 : 2;
}
if(two==null) {
return 3;
}
return isMatch(one,two) ? 4 : 5;
It can be done in one line using Java conditional operator:
return (one==null?(two==null?1:2):(two==null?3:(isMatch(one,two)?4:5)));
You can create a pseudo-lookup-table. Some people frown on the nested ternary operators and it's highly dependent on whitespace for readability, but it can be a very readable approach to conditional returning:
private int similarityCount (String one, String two) {
return (one == null && two == null) ? 1
: (one == null && two != null) ? 2
: (one != null && two == null) ? 3
: isMatch(one, two) ? 4
: 5;
}
I like expressions.
private static int similarityCount (String one, String two) {
return one == null ?
similarityCountByTwoOnly(two) :
two == null ? 3 : (isMatch(one, two) ? 4 : 5)
;
}
private static int similarityCountByTwoOnly(String two) {
return two == null ? 1 : 2;
}
As an aside, I would probably challenge why you are doing this. I would assume you would do some kind of check on the returned integer after you've evaluated it and branch your logic based on it. If that is the case, you've just made a less readable check for null where the user of your method needs to understand the contract implicit in the value of the integer.
Also, here's a simple solution for when you need to check if strings are equal when they may be null:
boolean same = one == null ? two == null : one.equals(two);
Getting rid of IF statements is good fun. Using a Map is one way of doing this. It doesn't fit this case exactly because of the call to isMatch, but I offer it as an alternative which cuts the similarityCount method body to a single line with one IF
The following code has two IFs. If GetOrDefault didn't evaluate the second argument, it could be reduced to one. Unfortunately it does so the null check inside isMatch is necessary.
You could go a lot further with this if you wanted to. For example, isMatch could return 4 or 5 rather than a boolean which would help you simplify further.
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.Map;
public class SimilarityCount {
private Map<SimilarityCountKey, Integer> rtn = ImmutableMap.of(new SimilarityCountKey(null, null), 1, new SimilarityCountKey(null, ""), 2, new SimilarityCountKey("", null), 3);
public int similarityCount(String one, String two) {
return rtn.getOrDefault(new SimilarityCountKey(one, two), isMatch(one, two) ? 4 : 5);
}
private boolean isMatch(String one, String two) {
if (one == null || two == null) {
return false;
}
return one.equals(two);
}
private class SimilarityCountKey {
private final boolean one;
private final boolean two;
public SimilarityCountKey(String one, String two) {
this.one = one == null;
this.two = two == null;
}
#Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
}
In case anyone else fancies a crack at another solution, here are some tests to help you get started
import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
public class SimilarityCountTest {
#Test
public void one(){
Assert.assertThat(new SimilarityCount().similarityCount(null,null), is(1));
}
#Test
public void two(){
Assert.assertThat(new SimilarityCount().similarityCount(null,""), is(2));
}
#Test
public void three(){
Assert.assertThat(new SimilarityCount().similarityCount("",null), is(3));
}
#Test
public void four(){
Assert.assertThat(new SimilarityCount().similarityCount("",""), is(4));
}
#Test
public void five(){
Assert.assertThat(new SimilarityCount().similarityCount("a","b"), is(5));
}
}
This should be slightly faster if neither is null, as it only performs one 'if' statement in this case.
private int similarityCount (String one, String two) {
if (one == null || two == null) { // Something is null
if (two != null) { // Only one is null
return 2;
}
if (one != null) { // Only two is null
return 3;
}
return 1; // Both must be null
}
return isMatch(one, two) ? 4 : 5;
}
I need to check if all values in a map are equal. I have a method to perform this task but would like to use a library or native methods. Limitations: Java 5 + Apache Commons libraries.
public static boolean isUnique(Map<Dboid,?> aMap){
boolean isUnique = true;
Object currValue = null;
int iteration = 0;
Iterator<?> it = aMap.entrySet().iterator();
while(it.hasNext() && isUnique){
iteration++;
Object value = it.next();
if(iteration > 1){
if (value != null && currValue == null ||
value == null && currValue != null ||
value != null && currValue != null & !value.equals(currValue)) {
isUnique = false;
}
}
currValue = value;
}
return isUnique;
}
What about this something like this:
Set<String> values = new HashSet<String>(aMap.values());
boolean isUnique = values.size() == 1;
how about
return (new HashSet(aMap.values()).size() == 1)
I know the original questions asks for solutions in Java 5, but in case someone else searching for an answer to this question is not limited to Java 5 here is a Java 8 approach.
return aMap.values().stream().distinct().limit(2).count() < 2
You could store the values in a Bidirectional Map and always have this property.
public static boolean isUnique(Map<Dboid,?> aMap) {
Set<Object> values = new HashSet<Object>();
for (Map.Entry<Dboid,?> entry : aMap.entrySet()) {
if (!values.isEmpty() && values.add(entry.getValue())) {
return false;
}
}
return true;
}
This solution has the advantage to offer a memory-saving short cut if there are many differences in the map. For the special case of an empty Map you might choose false as return value, change it appropriately for your purpose.
Or even better without a Set (if your Map does not contain null-values):
public static boolean isUnique(Map<Dboid,?> aMap) {
Object value = null;
for (Object entry : aMap.values()) {
if (value == null) {
value = entry;
} else if (!value.equals(entry)) {
return false;
}
}
return true;
}
As my comment above:
//think in a more proper name isAllValuesAreUnique for example
public static boolean isUnique(Map<Dboid,?> aMap){
if(aMap == null)
return true; // or throw IlegalArgumentException()
Collection<?> c = aMap.getValues();
return new HashSet<>(c).size() <= 1;
}
What is the best way to deal with null values, when doing Collections.sort() on nested objects?
I'd like to sort a couple of objects, basically applying this rule:
#Override
public int compare(final InvoicePos invoicePosOne, final InvoicePos invoicePosTwo) {
return invoicePosOne.getInvoice().getInvoiceNo().compareTo(invoicePosTwo.getInvoice().getInvoiceNo());
}
However, any of these objects can be null (i.e. invoice position, invoice and invoice number).
public class InvoicePos {
private Invoice invoice = null;
// ...
}
public class Invoice {
private String invoiceNo = "";
// ...
}
Do I have do do explicit null-checks on all my objects or is there an approach with less writing?
For clarification: I'm aware that my above example may raise NullPointerExceptions. Currently I'm doing the following and basically, I questioned myself, if there is any smarter approach.
Collections.sort(allInvoicePositions, new Comparator<InvoicePos>() {
#Override
public int compare(final InvoicePos invoicePosOne, final InvoicePos invoicePosTwo) {
if (null == invoicePosOne && null == invoicePosTwo) {
return 0;
}
if (null == invoicePosOne) {
return -1;
}
if (null == invoicePosTwo) {
return 1;
}
if (null == invoicePosOne.getInvoice() && null == invoicePosTwo.getInvoice()) {
return 0;
}
if (null == invoicePosOne.getInvoice()) {
return -1;
}
if (null == invoicePosTwo.getInvoice()) {
return 1;
}
if (null == invoicePosOne.getInvoice().getInvoiceNo() && null == invoicePosTwo.getInvoice().getInvoiceNo()) {
return 0;
}
if (null == invoicePosOne.getInvoice().getInvoiceNo()) {
return -1;
}
if (null == invoicePosTwo.getInvoice().getInvoiceNo()) {
return 1;
}
return invoicePosOne.getInvoice().getInvoiceNo().compareTo(invoicePosTwo.getInvoice().getInvoiceNo());
}
});
There is something called as NullComparator in org.apache.commons.collections.jar.
This might help you https://commons.apache.org/proper/commons-collections/javadocs/api-2.1.1/org/apache/commons/collections/comparators/NullComparator.html.
Do I have do do explicit null-checks on all my objects or is there an approach with less writing?
If these values don't represent anything in your collection, then the best thing you can do is avoid them; don't allow inserting them, so you won't have to handle them when comparing items.
If you insist to have them, then you must check if they're null to avoid NullPointerException.
If you have null values then you need to handle them explicitly and in a consistent way so to have a valid ordering relation. That is, something like:
compare (a, b) {
if (a == null && b == null) return 0;
if (a == null) return -1;
if (b == null) return +1;
return comp(a,b);
}
Don't be tempted to do something like:
compare (a, b) {
if (a == null || b == null) return -1;
return comp(a,b);
}
which would break the ordering relation.