I have a class like this..
Class A {
public void someNullCheckingMethod(Student stu) {
if (stu.getName() != null) {
String name = stu.getName();
} else {
// get name from other source(its something like
// fallback)
}
if (stu.getId() != null) {
String id = stu.getId();
} else {
// get id from other source(its something like
// fallback)
}
if (stu.getAddress() != null) {
String address = stu.getAddress();
} else {
// get address from other source(its something like
// fallback)
}
if (stu.getCity() != null) {
String city = stu.getCity();
} else {
// get city from other source(its something like
// fallback)
}
if (stu.getGender() != null) {
String gender = stu.getGender();
} else {
// get gender from other source(its something like
// fallback))
}
}
}
is there a way to avoid too many if statements? As you can see here I am checking null condition for each property but i don't want many checks to get desired result just want to reduce if conditions as well as want to get same desired result whatever I will get by putting all these if conditions.
Since you don't provide any context there's a few things you can do based on some assumptions.
Assumption one:
if the values are initialized as null
String name;
// or
String name = null;
Then you can just assign the values and ignore if the fields are null or not since the class members are null already.
String name = stu.getName(); // String name = "Some Name" OR null, depending on return value of method
Assumption two:
If you just want to avoid the if statements you can go with ternary operators
String name = stu.getName() != null ? stu.getName() : null; // Or some other default value
There are a few other methods that pops into my mind as well but without more context they are a bit useless at this point.
You could at least reduce the "verbosity" with Optional.
String name;
if (stu.getName() != null) {
name = stu.getName();
} else {
name = "default"
}
Would become
String name = Optional.ofNullable(stu.getName()).orElse("default");
Th choice is yours to return an Optional directly from the POJO Student for any value that could be null.
This would give a cleaner solution :
String name = stu.getName().orElse("default");
If getName looks like :
public Optional<String> getName(){
return Optional.ofNullable(name);
}
If using an external library is an option, then you should take a look at Dozer or MapStruct.
Related
I am writing test method like setTask(Task task). And Task object has several fields, e.g.
public String vehicle;
Method setTask should be used in different test-cases, so I'd like to have an options for this field to accept values:
null - the method should not do anything in this particulare case;
some string value - e.g. "", "Hello, World!", "Iso Isetta", ...
random - a value that indicates (as well as null indicates "no changes") that a random value should be selected for a drop-down list corresponding to this field.
So what can I do to make String to be SpecialString which could accept values null, random & some string value? (BTW: I don't want to set it to string value "RANDOM", and chech whether the value is equal to "RANDOM"-string)
UPDATE: I don't mean random like random value from a set of values, I mean random as well as null and this is for setTask() to handle random (select random from drop-down), and not to pass a random string from a set of values.
Pseudocode:
Task task = new Task();
task.vehicle = random; // as well as null
setTask(task)
in setTask(Task task):
if (task.vehicle == null) {
//skip
} else if (task.vehicle == random) {
// get possible values from drop-down list
// select one of them
} else {
// select value from drop-down list which is equal to task.vehicle
}
Don't assign a fixed String but use a Supplier<String> which can generate a String dynamically:
public Supplier<String> vehicleSupplier;
This, you can assign a generator function as you request:
static Supplier<String> nullSupplier () { return () -> null; }
static Supplier<String> fixedValueSupplier (String value) { return () -> value; }
static Supplier<String> randomSupplier (String... values) {
int index = ThreadLocalRandom.current().nextInt(values.length) -1;
return index > 0 && index < values.length ? values[index] : null;
}
In use, this looks like:
task.setVehicleSupplier(nullSupplier()); // or
task.setVehicleSupplier(fixedValueSupplier("value")); // or
task.setVehicleSupplier(randomSupplier("", "Hello, World!", "Iso Isetta"));
and you can get the String by
String value = task.vehicleSupplier().get();
or hide the implementation in a getter function
class Task {
// ...
private Supplier<String> vehicleSupplier;
public void setVehicleSupplier(Supplier<String> s) {
vehicleSupplier = s;
}
public String getVehicle() {
return vehicleSupplier != null ? vehicleSupplier.get() : null;
}
// ...
}
What you may want to do is to create an object that wraps a string as well as some information about whether or not it's a special value. Something along the lines of...
public class Special<T> {
public enum Type {
NOTHING, RANDOM, SPECIFIC
}
private final Type type;
private final T specificValue;
public Special(Type type, T specificValue) {
this.type = type;
this.specificValue = specificValue;
}
public Type getType() {
return type;
}
public T getSpecificValue() {
if (type != SPECIFIC) {
throw new IllegalStateException("Value is not specific");
}
return specificValue;
}
}
The class above could be used like so:
Special<String> a = new Special<>(Special.Type.NOTHING, null);
Special<String> b = new Special<>(Special.Type.SPECIFIC, "Hello");
if (b.getType() == Special.Type.RANDOM) {
// do something
}else if (b.getType() == Special.Type.SPECIFIC) {
String val = b.getSpecificValue();
// do something else
}
A slightly more polished variant of the thing above is probably the best way, but there is a way, a much uglier way, to do it using nothing but a String field.
What you could do is to have a "magical" string instance that behaves differently from all other string instances, despite having the same value. This would be done by having something like
static final String SPECIAL_VALUE_RANDOM = new String("random");
Note the use of the String constructor, which ensures that the string becomes a unique, non-interned instance. You can then say if (vehicle == SPECIAL_VALUE_RANDOM) { ... } (note the use of == instead of .equals()) to check if that specific instance (rather than any other string that says "random") was used.
Again, this is not a particularly good way of doing this, especially if you intend to do this more than once ever. I would strongly suggest something closer to the first way.
When my program comes to this method it never seems to update the target value. If I input "dave" it will remain "dave" no matter how many calls to the method are made.
public Person lookup(String name){
if(firstPerson == null){
return null;
}
Person target = null;
for (target = firstPerson; target != null; target = target.nextPerson){
if(name.equals(target.name)){
return target;
}
else {
return null;
}
}
return target; // replace this line
}
If I add a friend via this addFriend method firstFriend will end up printing whatever the last added name was. If the inputted named were rob bill and travis
The output would be travis travis travis.
public void addFriend(Person friend){
firstFriend = new Friend(friend, firstFriend);
return; // replace this line
public String friendString(){
String friendList = "";
if(firstFriend == null){
return null;
}
for(Friend pointer = firstFriend; pointer != null; pointer = pointer.nextFriend){
friendList = friendList + firstFriend.who.name + " ";
}
return friendList.trim(); // replace this line
}
You always return in the first iteration of the loop. If the person is found it's returned (the if branch), and if it isn't, null is returned (the else branch). Instead, you should keep iterating until you find the correct person or exhaust the list. The first condition, BTW, is a subset of the loop (if firstPerson is null target will just become null immediately), and can (should!) also be removed:
public Person lookup(String name){
Person target = null;
for (target = firstPerson; target != null; target = target.nextPerson) {
if (name.equals(target.name)) {
return target;
}
}
return target; // Or null explicitly - matter of taste.
}
if(name.equals(target.name)){
return target;
}
else {
return null;
}
The else part needs to go away. The effect of this code is that it only checks the first value and if it is not the value that you want to look up it is coming out straight away.
Change
return target; // replace this line
to return null;
and remove the else part mentioned above
I'm new to java and i want to do a condition check and return a message
PersonalDetails Request: It holds the value for all the below infos
getID();
getName();
getDesignation();
getHomeAddress();
getOfficeAddress();
getEmailID();
getMobile();
getHomePhone();
getOfficePhone();
i want to check all values for empty then return message.
Like "Your ID,Name, Mobile cannot be empty" if i pass empty values to ID, Name, Mobile
Below is the sample snippet which has to do the check for all PersonalDetails Request
public static String checkValue(PersonalDetails Request) {
String str="Your ";
if(request.getID().isEmpty())
{
str="ID,";
}
if(request.getName().isEmpty())
{
str="Name";
}
if(request.getDesignation().isEmpty())
{
str="Designation";
}
if(request.HomeAddress.isEmpty())
{
str="Address";
}
str+= "cannot be empty"
return str;
}
Is this right or any other easy approach will address the issue
Thanks in advance
No if the string contains null then it will through a null pointer exception.
You first need to check it for null then for Empty.
Can we rely on String.isEmpty for checking null condition on a String in Java?
There are multiple suggestions for your code:
Use camel-case for variables, methods etc. in your code. For example parameter should be named as PersonalDetails request and not PersonalDetails Request. These are standard coding conventions. Also getter/setter should follow the rules, check HomeAddress which seems to miss it.
Use StringBuilder class as it performs better specially in case of appending while in a loop.
You need to check for null before performing any operation else you will be facing a NullPointerException. You can also read about Optional in Java 8.
The code can be improved like:
public static String checkValue(PersonalDetails request) {
if(null == request ) {
//Throw exception or log/return message as per your need.
}
int some_appropriate_size = 50; // You need to decide about some_appropriate_size so that it starts with enough capacity for the full content we are going to append.
StringBuilder stringBuilder = new StringBuilder(some_appropriate_size);
stringBuilder.append("Your ");
if(null!= request.getID() && request.getID().isEmpty())
{
stringBuilder.append("ID,");
}
if(null!= request.getName() && request.getName().isEmpty())
{
stringBuilder.append("Name");
}
if(null!= request.getDesignation() &&request.getDesignation().isEmpty())
{
stringBuilder.append("Designation");
}
if(null!= request.getHomeAddress() && request.getHomeAddress().isEmpty())
{
stringBuilder.append("Address");
}
stringBuilder.append( "cannot be empty");
return stringBuilder.toString();
}
Your condition is correct but you forget to concat string in each if. If don't concate it will not have existing value but new value only.
public static String checkValue(PersonalDetails Request) {
String str="Your ";
if(request.getID().isEmpty())
{
str= str + "ID,";
}
if(request.getName().isEmpty())
{
str= str + "Name";
}
if(request.getDesignation().isEmpty())
{
str= str + "Designation";
}
if(request.HomeAddress.isEmpty())
{
str= str + "Address";
}
str+= "cannot be empty"
return str;
}
My suggestion will be to use StringBuilder to get better performance.
Here it's better to check not only isEmpty. It's better to check null, " " or "-" as well.
Before you check isEmpty or "-" or " ", make sure to check null to avoid getting NullPointerException
i want to find a name in a recursivly build itemlist.
Items can have subitems which can have subsubitems etc.
For the first level it worked. for deeper levels the correctly found name/id mapping gets an overwrite from the stack. Because of the string result, i have to write the return statement at the end. So i have a mental blockage how i can solve this problem. I appreciate for your help.
public String getNameForID(List<Item> top, long id, String name ) {
for (Item i : top) {
if (i.getId() == id) {
name = i.getName();
return name;
}else{
this.getNameForID(i.getSubItemsList(), id,name);
}
}
return name;
}
This must be what you're looking for:
public String getNameById(List<Item> items, long id) {
// boundary condition
if (items == null || items.isEmpty()) {
return null;
}
// looping
for (Item item : items) {
// if current is
if (item.getId() == id) {
return item.getName();
}
// recursion
String name = getNameById(item.getSubItemsList(), id);
// if nested found
if (name != null) {
return name;
}
}
// boundary condition
return null;
}
Your recursive call to getNameForID must also be able to return a value. It also needs to be able to indicate that no value was found so that the recursion is terminated.
Based on #sp00m's previously deleted (and slightly incorrect) answer, try this:
public String getNameById(List<Item> items, long id) {
// sanity checking conditions to terminate recursion early
if (items == null || items.isEmpty()) {
return null;
}
// iterate over collection
for (Item item: items) {
if (item.getId() == id) {
return item.getName();
} else {
String name = getNameById(item.getSubItemsList(), id);
if (name != null) {
return name;
}
}
}
// final termination condition - entry wasn't in this list
return null;
}
you do not assign the value returned here to name:
this.getNameForID(i.getSubItemsList(), id,name);
actually you don't need the parameter name - just return name or null in each call
My issue is related to design currently. I am having a jsf parameter page and it submits
different parameters to generate a jasper report. E.g. Nationality, Travel type, Visa type,
Gender and so on. Parameters can be a combination. E.g. At one time user can select
nationality and visatype and leave others blank which will make other's default to the value
of ALL. I submit the id's from the parameter page. If nothing was selected by the user i am
setting the values manually to ALL in the setter methods. Here is a snapshot of my managed
bean method and the POJO.
private ReportBean generateReportBean(TravelDetailSearchParams searchParams, String reportPath){
TravelDetailReportBean travelDetailReportBean = new TravelDetailReportBean();
if(searchParams.getGender().getId() != 0){
for(Lookup lookup : gender){
if(lookup.getId() == searchParams.getGender().getId()){
travelDetailReportBean.setGender(lookup.getDescEnglish());
break ;
}
}
}
else{
travelDetailReportBean.setGender(searchParams.getGender().getDescEnglish());
}
if(searchParams.getTravelType().getId() != 0){
for(Lookup lookup : travelType){
if(lookup.getId() == searchParams.getTravelType().getId()){
travelDetailReportBean.setTravelType(lookup.getDescEnglish());
break ;
}
}
}
else{
travelDetailReportBean.setTravelType(searchParams.getTravelType().getDescEnglish());
}
if(searchParams.getPort().getId() != 0){
for(Lookup lookup : port){
if(lookup.getId() == searchParams.getPort().getId()){
travelDetailReportBean.setPort(lookup.getDescEnglish());
break ;
}
}
}
else{
travelDetailReportBean.setPort(searchParams.getPort().getDescEnglish());
}
if(searchParams.getNationality().getId() != 0){
for(Lookup lookup : country){
if(lookup.getId() == searchParams.getNationality().getId()){
travelDetailReportBean.setCountry(lookup.getDescEnglish());
break ;
}
}
}
else{
travelDetailReportBean.setCountry(searchParams.getNationality().getDescEnglish());
}
if(searchParams.getVisaType().getId() != 0){
for(Lookup lookup : visaType){
if(lookup.getId() == searchParams.getVisaType().getId()){
travelDetailReportBean.setVisaType(lookup.getDescEnglish());
break ;
}
}
}
else{
travelDetailReportBean.setVisaType(searchParams.getVisaType().getDescEnglish());
}
logger.debug("nationality: " + travelDetailReportBean.getCountry());
logger.debug("travelType: " + travelDetailReportBean.getTravelType());
logger.debug("visatype: " + travelDetailReportBean.getVisaType());
logger.debug("port: " + travelDetailReportBean.getPort());
travelDetailReportBean.setReportName(BorderEntryExitConstants.TRAVEL_DETAIL_REPORT_NAME);
travelDetailReportBean.setReportPath(reportPath);
return travelDetailReportBean ;
}
The POJO code is shown below
public class TravelDetailReportBean extends ConcreteReportBean {
private String gender ;
private String travelType ;
private String port ;
private String country ;
private String visaType;
public String getGender() {
return gender;
}
public void setGender(String gender) {
if(gender == null || gender.equals("")){
this.gender="ALL";
}
else{
this.gender = gender;
}
}
public String getTravelType() {
return travelType;
}
public void setTravelType(String travelType) {
if(travelType == null || travelType.equals("")){
this.travelType ="ALL";
}
else{
this.travelType = travelType;
}
}
public String getPort() {
return port;
}
public void setPort(String port) {
if(port == null || port.equals("")){
this.port ="ALL";
}
else{
this.port = port;
}
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
if(country == null || country.equals("")){
this.country ="ALL";
}
else{
this.country = country;
}
}
public String getVisaType() {
return visaType;
}
public void setVisaType(String visaType) {
if(visaType == null || visaType.equals("")){
this.visaType ="ALL";
}
else{
this.visaType = visaType;
}
}
}
Issue is the generateReportBean method. i am putting to many if's to see if the id is not
zero get the description of that id from lookup else just set it like that and inside bean
setter i am checking for null. If null setting it to ALL.
My issue is currently i have few parameters and these if's can work for a while but what
if the search parameter grow. THe if's will look ugly. Can someone suggest me a better approach
to get rid of these if's.
Thanks,
Peter
If Lookup is List of objects then you can provide equals method based on id and then you can directly do
if(lookup.contains(searchParams.getTravelType()))
{
//code here
}
Follow Chain of Responsibility design pattern.
This will increase the code readability and maintainability
Reduces the number of "if" loops
Ref: http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
Divide the parsing pieces into different functions. eg.
checkgender(searchParams.getGender(), travelDetailReportBean);
or
travelDetailReportBean.setGender(checkgender(searchParams.getGender()));
Depends on how you want it
Yes you can put these methods into a utility class and do as Minion has suggested.
travelDetailReportBean.setGender(ParamUtil.checkGender(searchParams.getGender());
Putting validation condition in a dto as you have done is not a smart coding move. Is it a generic
parameter screen you are trying to make? Mostly, every report should have a separate parameter
screen if every report parameters differ.
HTH,
Ben
IMHO testing for empty/null Strings is too common to code it manually. I like to use StringUtils from Apache Commons lang to simplify it. Combined with Java's ? operator, you can write it much clearer:
private static final String OPTION_ALL = "ALL";
public void setGender(String gender) {
this.gender = StringUtils.isEmpty(gender) ? OPTION_ALL : gender;
}
Of course, if you have a large number of fields a generic approach may be justified.
EDIT: Conceptual consideration
As I see, you perform value checking in the classes setter methods. I would advise against doing so: I expect setters to only assign a value to an instance variable. If they do more, this might lead to confusion. You are probably using the class to parametrize some search function, so a better place for ensuring non-empty member values would be right before performing that search.
You may also annotate the fields that you need to do a lookup and then use a single loop to see their values in searchParams and if id is present, do a lookup.