I have a function which accepts two parameters, foo(A a, String type) depending on type I have to change the if statement condition.
foo(A a, String type){
//if type equals 'bar'
if(!a.isEmpty() && a.hasMember()){...}
//but if type is something else
if(!a.isEmpty() || a.hasMember()){...}
}
the logic in the if body is the same pretty much everything else is the same except the condition is there any efficient way to implement the difference or I have to write everything twice?
I suppose you can use the following:
foo(A a, String type){
//if type equals 'bar'
if("bar".equals(type)) {
if(!a.isEmpty() && a.hasMember()){...}
}
else {
//but if type is something else
if(!a.isEmpty() || a.hasMember()){...}
}
}
Explanation: If type has value "bar" then if condition becomes true and then whatever code you want for that condition will be executed.
You can also use concise form:
if( ("bar".equals(type) && (!a.isEmpty() && a.hasMember())) || (!"bar".equals(type) && (!a.isEmpty() || a.hasMember()))) {
// Do your stuff
}
The point to note is "bar".equals(type) is better than type.equals("bar") as it also saves you from hassle of the case when type is null.
Combine the predicates with an || and make the check of type in each condition part.
if (type.equals("bar") && !a.isEmpty() && a.hasMember()) || (!type.equals("bar") && (!a.isEmpty() || a.hasMember())) {
//do your thing
}
If null is a possible value of type, then it is possible to change the check to "bar".equals(type) to avoid a NullPointerException.
You could use a map with key type, and value should be object that have you type related logic.
foo(A a, String type) {
typesMap.get(type).execute(a);
}
class TaskImpl implements Task { // each task should behave as it should be
#override
public void execute(A a) {
if(!a.isEmpty() && a.hasMember()) {...}
}
}
Related
I started recently as a developer and I am still struggling a bit with the way I write my code.
Is there a better way to write this two if-statements? How would you write it and why?
Java code:
#Override
#Transactional
public void deleteItem(final ConfigurationType type, final long itemId, final boolean force) {
this.applicationNameUtils.throwOnInvalidApplication(type.getApplication());
final ConfigurationItemModel item =
this.configurationItemRepository.findByApplicationAndTopicAndId(type.getApplication(), type.getTopic(), itemId)
.orElseThrow(() -> new ResourceNotFoundException(itemId, "Configuration Item"));
if (Boolean.TRUE.equals(item.getContentModificationOnly()) && Boolean.FALSE.equals(force)) {
throw new ContentModificationOnlyException("Configuration Item cannot be deleted");
}
if ((Boolean.TRUE.equals(item.getContentModificationOnly()) || Boolean.FALSE.equals(item.getContentModificationOnly())) && Boolean.TRUE.equals(force)) {
this.assignmentService.deleteAssignmentsByItem(item);
this.configurationInstanceRepository.deleteByItem(item);
this.configurationItemRepository.deleteById(itemId);
}
}
I am not sure if I can somehow combine this two in a if-else.
It looks like you don't care about item.getContentModificationOnly() is true or false in the second if-statement since your code is (Boolean.TRUE.equals(item.getContentModificationOnly()) || Boolean.FALSE.equals(item.getContentModificationOnly()). So if your logic is right I suggest you code like this:
if (fore) {
this.assignmentService.deleteAssignmentsByItem(item);
this.configurationInstanceRepository.deleteByItem(item);
this.configurationItemRepository.deleteById(itemId);
} else if (Boolean.TRUE.equals(item.getContentModificationOnly()) {
throw new ContentModificationOnlyException("Configuration Item cannot be deleted");
}
First if condition
if (item.getContentModificationOnly() && !force) {
Second If condition
if ((item.getContentModificationOnly() || !item.getContentModificationOnly()) && force) {
The below code will always return true
(item.getContentModificationOnly() || !item.getContentModificationOnly())
so modify second if stmnt to just
if (force){
Depends on the return type item.getContentModificationOnly(). If it's Boolean, than the second statement can be reduced to
if(item.getContentModificationOnly() != null && force)
If the return type of item.getContentModificationOnly() is boolean, than the statement can be reduced to
if(force)
and the answer of #LiLittleCat above if correct.
I am new to Java. I am facing an issue now in which I couldn't find the easiest and cleanest way of solving it.
Suppose I have 3 parameters(string) passed to a function(could be a Hashmap too).I want to check if individual variable or combination of variables is not Null and act accordingly.
For example one way to do this is using if-else this way
if(a!=null && b == null && c == null) {
//doSomething
}
else if(a==null && b!= null && c == null ) {
//doSomething
}
else if(a==null && b0= null && c != null) {
//doSomething
}
......
//Similarly combination of two variables
if(a!=null && b != null && c == null) {
//doSomething
}
else if(a!=null && b== null && c != null) {
//doSomething
}
else if(a==null && b!= null && c != null) {
//doSomething
}
......
//and so on
//Similarly combination of three variables
if(a!=null && b != null && c != null) {
//doSomething
}
....
How to achieve this kind of situation. I found similar question, but didn't make the code clean. Any help will be appreciated
Write these utility functions and you can compare n terms easily.
public static boolean areAllNull(Object... objects) {
return Stream.of(objects).allMatch(Objects::isNull);
}
public static boolean areAllNotNull(Object... objects) {
return Stream.of(objects).allMatch(Objects::nonNull);
}
you can use these functions for n comparisons.
if(areAllNotNull(a) && areAllNull(b,c)) {
//doSomething
}
else if(areAllNotNull(b) && areAllNull(a,c)) {
//doSomething
}
else if(areAllNotNull(c) && areAllNull(b,a)) {
//doSomething
}
This is my solution. Note, that you have multiple if...else in one single method. And then you add doSomething. This is going to be terrible to ready and later to realize.
What about to move one single condition into separate method and name it with relative name. Then, lets encapsulate it into Consumer and all of it into a predefined list. Later, if your doSomething will be huge, then you can move from single method to single class, not modifying client code.
This is class, to collect required variable for conditions:
final class Data {
private final String a;
private final String b;
private final String c;
}
Then define one Consumer per on if statement:
Consumer<Data> wonderfulConsumer = data -> {
if (a != null && b == null && c == null) {
// do something for wonderful consumer
}
};
Consumer<Data> badLuckConsumer = data -> {
if (a == null && b != null && c == null) {
// do something for bad luck consumer
}
};
Note, all these consumers could be modified separately (even be in the different classes).
Then in the client code, define list of all known consumers: List<Consumer<Data>> consumers = Arrays.asList(wonderfulConsumer, badLuckConsumer).
And finally your method will be like this and you do not need to change it when you decide to modify or add consumers.
Data data = new Data(a, b, c);
consumers.forEach(consumer -> consumer.accept(data));
If I had to do this , i will do it in the same way that you have done.
but if you dont like that and if you think it is not readable you can do it in this way, i expect lot of negative comments to this answer because this is a bad solution.
public static void yourMethod(Object a,Object b,Object c)
{
int evaluation = howManyNotNull(a,b,c);
if(evaluation == 0) // all are nulls
{
// your code
}
else if(evaluation == 1) // only one is not null
{
if(a!=null)
{
}
else if(b!=null)
{
}
else
{
// c not null
}
}
else if(evaluation == 2) // two variables are not null but other one is null
{
if(a==null)
{
}
else if(b == null)
{
}
else
{
// c is null, a and b not null
}
}
else
{
// all abc not null
}
}
private static int howManyNotNull(Object a, Object b, Object c)
{
return (a==null?0:1) + (b==null?0:1) + (c==null?0:1);
}
There is extended version of this , assign 3 prime values for a, b , c (example :a=2,b=3,c=5), then use a supportive method like this
private static int convertAvailabilityToInt(Object a, Object b, Object c)
{
return (a==null?1:2) * (b==null?1:3) * (c==null?1:5);
}
if the answer is 1 ,then all are not null .
You can use for example a 3 digit string simulating 3 flags.
You first set it to "000".
Then you check each variable for null, if it is not you will replace the 0 with 1.
Then you could use switch cases to treat each case.
You are doing everything right but you have to remember that primitive data types cannot be null. For example string is not null, but empty string "", or int cannot be null, its by default sets to 0. In conclusion Objects like Map , ArrayList or Integer.. you can check for null, but primitive data types cannot be null, so you cannot check them for it. For deeper understanding just learn about primitive and advanced data types.
I hope I got your problem right :)
If i have 5 optional parameters that be passed by GET API call how can i filter the array of JSON and get desired results.
Basically if all 5 parameters are passed i can check in an 'ANDED' IF statement as follows
if (obj.get(address).toString().contains(searchRequest.getAddress())
&& obj.get(car).toString().equalsIgnoreCase(searchRequest.getCar())
&& properties.get(name).toString().equalsIgnoreCase(searchRequest.getName())
&& properties.get(job).toString().equalsIgnoreCase(searchRequest.getJob())
&& properties.get(salary).toString().equalsIgnoreCase(searchRequest.getSalary())
searchRequest contains 5 fields which can optional be passed to GET REST call which will work fine, but if only two fields are passed which is allowed how can i build up correct ANDED IF statement so for example if only searchRequest.getAddress() and searchRequest.getName() are passed i would want
if (obj.get(address).toString().contains(searchRequest.getAddress())
&& obj.get(name).toString().equalsIgnoreCase(searchRequest.getName())
and ignore the other 3 fields
Use a comparison method:
public static <T> boolean equalsIgnoreCase(T a, T b) {
if (a == b) {
return true;
} else if (a == null || b == null) {
return false;
} else {
return a.toString().equalsIgnoreCase(b.toString());
}
}
If I have to make a different database query depending on the presence or not of different parameters, which would be the correct design pattern to avoid too many if-else with the different combinations ?
Let's say I have parameters a, b, c (the amount can grow in the future), I'm using repositories so I would have to make a call something like this
public Foo getFoo(String a, String b, String c){
Foo foo;
if(a!=null && !a.isEmpty() && b!=null && !b.isEmpty() && c!=null && !c.isEmpty())
foo = repository.findByAAndBAndC(a,b,c);
if((a==null || a.isEmpty()) && b!=null && !b.isEmpty() && c!=null && !c.isEmpty())
foo = repository.findByBAndC(b,c);
if((a!=null && !a.isEmpty()) && (b==null || b.isEmpty()) && c!=null && !c.isEmpty())
foo = repository.findByAAndC(a,c);
if((a==null || a.isEmpty()) && (b==null || b.isEmpty()) && !b.isEmpty() && c!=null && !c.isEmpty())
foo = repository.findByC(c);
if((a==null || a.isEmpty()) && (b==null || b.isEmpty()) && !b.isEmpty() && (b==null || b.isEmpty()))
foo = repository.findOne();
etc.
.
.
.
return foo;
}
How can that be better structured ?
At the beginning, I would propose you the Specification design pattern that :
is a particular software design pattern, whereby business rules can be
recombined by chaining the business rules together using boolean
logic. The pattern is frequently used in the context of domain-driven
design.
but your actual code doesn't suit completely to that as you don't invoke the same method of the repository according to the case.
So I think that you have two ways :
1) Refactoring your repository to provide a single common method accepting a specification parameter and able to handle the different cases.
If you use Spring, you could look at the JpaSpecificationExecutor interface that provides methods such as :
List<T> findAll(Specification<T> spec)
Even if you don't use Spring, I think that these examples could help you .
2) If you cannot refactor the repository, you should look for another way and provide a abstraction level about which repository methods/parameters may be passed to.
Actually, you invoke a different method with different parameters according to the input parameters but in any case you return the same type of object to the client of the method : Foo. So to avoid conditional statements, polymorphism is the way to follow.
Each case to handle is finally a different strategy. So you could have a strategy interface and you could determine the strategy to use to return the Foo to the client.
Besides, as suggested in a comment : a!=null && !a.isEmpty() repeated multiple times is not a good smell. It makes much duplication and also makes the code less readable. It would better to apply this processing by using a library such as Apache common or even a custom method.
public class FooService {
private List<FindFooStrategy> strategies = new ArrayList<>();
public FooService(){
strategies.add(new FindFooByAAndBAndCStrategy());
strategies.add(new FindFooByBAndCStrategy());
strategies.add(new FindFooByAAndCStrategy());
strategies.add(new FindFooByCStrategy());
}
public Foo getFoo(String a, String b, String c){
for (FindFooStrategy strategy : strategies){
if (strategy.isApplicable(a, b, c)) {
return strategy.getFoo(a, b, c);
}
}
}
}
Where FindFooStrategy is defined as :
public interface FindFooStrategy{
boolean isApplicable(String a, String b, String c);
Foo getFoo(String a, String b, String c);
}
And where each subclass defines its rules. For example :
public class FindFooByAAndBAndCStrategy implements FindFooStrategy{
public boolean isApplicable(String a, String b, String c){
return StringUtils.isNotEmpty(a) && StringUtils.isNotEmpty(b) &&
StringUtils.isNotEmpty(c);
}
public Foo getFoo(String a, String b, String c){
return repository.findByAAndBAndC(a,b,c);
}
}
This is not a complete answer. I will offer several suggestions to address the problem at hand.
Dealing with Null Values
To avoid checking whether a value is null, I suggest that you use a container class for your String query parameters with some method, say getValue() that returns parameter's value e.g., parameter='value' if the value is present or some default string value e.g., parameter like '%' if it's null. This approach follows the so-called, Null Design Pattern.
Dynamic Construction of Query
After doing this, it will no longer matter what values the parameters you passed have and you can just construct your condition iteratively such as:
for parameter in parameters:
condition = "AND" + parameter.getValue()
Perhaps you can combine this with a generic method for querying that accepts arbitrary length condition such as:
repository.findBy(condition)
I am not 100% sure since I am typing this answer from the top of my mind but I think this approach works and should be able to address the problem mentioned in your post. Let me know what you think.
You can make use of a enum defining bitmap-constants with a valueOf method:
public enum Combinations{
A_AND_B_AND_C (0b111),
B_AND_C (0b110),
A_AND_C (0b101),
C (0b100),
A_AND_B (0b011),
B (0b010),
A (0b001),
NONE (0b000),
;
private final int bitmap;
Combinations(int bitmap){
this.bitmap = bitmap;
}
public static Combinations valueOf(String... args){
final StringBuilder builder = new StringBuilder();
for(int i = args.length - 1; i >= 0; i--){
final String arg = args[i];
builder.append(arg != null && !arg.isEmpty() ? '1' : '0');
}
final int bitmap = Integer.parseInt(builder.toString(), 2);
final Combinations[] values = values();
for(int i = values.length -1; i >= 0; i--){
if(values[i].bitmap == bitmap){
return values[i];
}
}
throw new NoSuchElementException();
}
}
And another class which has a switch case statement:
public class SomeClass {
public Foo getFoo(String a, String b, String c){
switch(Combinations.valueOf(a, b, c)){
case A_AND_B_AND_C:
return repository.findByAAndBAndC(a, b, c);
case B_AND_C:
return repository.findByBAndC(b, c);
/* all other cases */
case NONE:
return repository.findOne();
default:
// type unknown
throw new UnsupportedOperationException();
}
}
}
This may be a lot of work in the first place. But you'll be glad when you've done it. By using Bitmaps you can have a lot of combinations. The valueOf method takes care of finding out which combination actually should be taken. But what should happen after can't be done generically. So when adding another parameter d you'll get a lot more combinations which must be added to the enum.
All in all this solution is overkill for small amounts of parameters. Is still quite easy to understand, because the logic is split up into many small parts. You just still don't get around the big switch statement at the end though.
I am trying to split single line if statement into multiline if statement with the same meaning. I have:
if(a || (b && c))
{
/* do smt */
}
but would like to change it to something like if I would have
if(a && b && c)
{
/*do smt*/
}
with the same meaning of
if(a)
{
if(b)
{
if(c)
{
/* do smt */
}
}
}
Thanks!
Boolean algebra can turn this condiiton
a || (b && c) into
(a || b) && (a || c)
so you can do somthing like:
if(a || b)
{
if(a || c){
/* do smt */
}
}
You can't really do this without repeating the body of the if block. You can transform a || b to !(!a && !b), but while this uses an &&, you can't split this up into nested if statements due to the surrounding !(...).
Why do you want to do this in the first place? My assumption would be that the three conditions a, b and c are very long and/or complex. If this is the case, I'd suggest one of the following:
declare three boolean variables with descriptive names and use those in the condition
boolean isLoggedIn = // some really long data base lookup
boolean isGuest = // more data base stuff
boolean guestCanEdit = // a complex boolean expression
if (isLoggedIn || (isGuest && guestCanEdit)) { ...
define three methods performing the above checks and use those in the if
if (isLoggedIn(user) || (isGuest(user) && guestCanEdit(topic))) { ...
Note, however, that the first version does not use short-circuiting, i.e. all the conditions will be evaluated, even if the first is already true or the second is false. This should be avoided if any of the conditions in computationally expensive or e.g. if the third check is only possible if the second succeeds (e.g. after a null check).
Concerning your comment: The condition
if (list.isEmpty() ||
(!list.isEmpty() && list.getLast().compareTo(heap.peek().value) <= 0))
is not really that long, and I would not suggest any of the above methods for this, as it will not get much shorter that way. But you can shorten it, because the b part is redundant. Due to the short-circuiting of ||, (b && c) are only evaluated if !a, and since your b is !a, you can shorten it to just a || c
if (list.isEmpty() || list.getLast().compareTo(heap.peek().value) <= 0)
If your goal is to count how many times compareTo is called, you can use this:
if (! list.isEmpty() && list.getLast().compareTo(heap.peek().value) <= 0)
Now this is just b && c, with the a part entirely missing. Note that this is not equivalent to a || (b && c) anymore, but in this case that's a good thing, because due again to the short-circuiting, compareTo would actually not be called in a || c if a already evaluated to true.
The need for this is not very clear, but you could do this: Make it in a function:
function codeToDo() {
// your code to execute on condition
}
if (a) {
codeToDo();
else if (b) {
if (c) {
codeToDo();
}
}
if(a || b)
{
if(a || c){
/* do smt */
}
}
To further handle if(a||b) part, apply:
if(a){
/*do task1*/
}else if(b){
/*do task1*/
}
Note that in the if(a) as well as else if(b), you are running same code;i.e. task1.
Yes you can do this, but perhaps you shouldn't.
if (a && b) statement;
is exactly equivalent to
if (a){
if (b){
statement;
}
}
But the same can't be said for if (a || b): you'd need to write statement; in more than one place:
if (a){
statement;
} else if (b){
statement;
}
That said, || does distribute across &&, even with the short-circuiting property:
So
if (a || b && c/*redundant parentheses removed*/){
statement;
}
can be written as
if ((a || b) && (a || c)){
statement;
}
which, from above, is
if (a || b){
if (a || c){
statement;
}
}
which, although unnecessarily obfuscated, is what you want.