I have this piece of code:
public LatLng[] locationDtoListToLatLngArray(List<LocationDto> locationDtoList) {
return locationDtoList.stream()
.map(locationDto -> new LatLng(locationDto.getLatitude(), locationDto.getLongitude()))
.toArray(LatLng[]::new);
}
but is crashing if locationDto is null inside .map
I fixed it doing this:
public LatLng[] locationDtoListToLatLngArray(List<LocationDto> locationDtoList) {
return locationDtoList.stream()
.map(locationDto -> locationDto == null ? null : new LatLng(locationDto.getLatitude(), locationDto.getLongitude()))
.toArray(LatLng[]::new);
}
but I want to know if there is a better approach (without checking if locationDto == null)
Please note that, if locationDto == null, I want to keep the null, so filter is not an option :)
Thanks
EDIT: I know that the problem is accessing a null object, I just want to know is if there is some function like .map(), that do what I need, .mapKeepingNulls(), something like that.
EDIT 2: I ended up doing this:
public LatLng[] locationDtoListToLatLngArray(List<LocationDto> locationDtoList) {
return locationDtoList.stream()
.map(this::locationDtoToLatLng)
.toArray(LatLng[]::new);
}
private LatLng locationDtoToLatLng(LocationDto locationDto) {
if (locationDto == null) {
return null;
}
return new LatLng(locationDto.getLatitude(), locationDto.getLongitude());
}
The problem is that you are accessing methods of a potentionally null value. If you really don't want the null check there (which I think is a good solution) you can try making a static method in LatLng that will take the LocationDto and return the right instance or null when the supplied LocationDto is null.
Something like this:
public static LatLng getFromLocationDto(LocationDto ldt){
if(ldt == null)
return null;
return new LatLng(ldt.getLatitude(), ldt.getLongitude());
}
But the null check has to be somewhere (unless you can ensure that there will be no null int the locationDtoList).
The issue as little to do with Java 8 streams. You are getting an NullPointerException when doing locationDto.getLatitude().
It is totally normal to check for null value. If you were not in a stream, I am almost sure that you would have not disturbed you.
Maybe what you dislike is the fact that you are performing inline conditional operation in a one-liner, in which case I advise you to use an helper function like _createLatLng(LocationDto locationDto) to externalize that process.
You can make use of Optional, which is a new class in Java 8 made for this purpose.
// transform locationDtoList to a list of Optional
locationDtoList.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.map(locationDto -> new LatLng(locationDto.getLatitude(), locationDto.getLongitude()))
.toArray(LatLng[]::new);
Related
I want to create method, which will use Optional functionality and return value NodeId.
This value I should extract from Asset object.
In some case I already use some functionality like ifPresent, filter, flatMap. But now I want clearly understand whether can I use Optional with simple methods like in example below, where I need just extract value from another Object
First example supposedly not very nice but however I try to Use Optional:
public Optional<NodeId> findParentNodeIdByAsset(Asset asset) {
Optional<Asset> tmpAsset = Optional.ofNullable(asset);
if(tmpAsset.isEmpty()) {
throw new NullPointerException();
}
return Optional.ofNullable(tmpAsset.get().getParents().iterator().next());
}
In second example I try to write same things but without Optional:
public NodeId tmpFindParentNodeIdByAsset(Asset asset) {
if(Objects.isNull(asset)) {
throw new NullPointerException();
}
return asset.getParents().iterator().next();
}
There's no point to check for null asset or empty tmpAsset if you're going to throw NullPointerException in these cases.
Just write:
public NodeId tmpFindParentNodeIdByAsset(Asset asset) {
return asset.getParents().iterator().next();
}
and the NullPointerException will be thrown if you try to de-reference a null reference.
Now, using an Optional becomes useful if you don't want to throw NullPointerException or if asset is not the only reference that may be null.
For example, suppose that asset.getParents() can also be null, and in case either asset or asset.getParents() are null, you want to return some default value, or an empty Optional.
You can chain multiple map() calls to transform each potentially null reference to the next potentially null reference, and end with either an Optional (as in the example below), a default value or an exception.
public Optional<NodeId> findParentNodeIdByAsset(Asset asset) {
return Optional.ofNullable(asset)
.map(asset -> asset.getParents())
.map(parents -> parents.iterator().next());
}
In addition, it might be safer to check that parents is not empty before trying to obtain the first element of its Iterator.
You aren't exactly using Optional correctly in your first method, it doesn't make much sense to throw a NullPointerException in the method where you're returning Optional. See Eran's answer for proper use.
If you, however, do want to throw a NullPointerException when the input is null, then would use this instead:
public NodeId tmpFindParentNodeIdByAsset(Asset asset) {
Objects.requireNonNull(asset, "asset");
return asset.getParents().iterator().next();
}
By using Optional you ensure the caller being aware of the returned value might be null.
Using Optional makes the code more fluent and improves its readability.
In your case i would indeed use a Optional. For example:
public NodeId tmpFindParentNodeIdByAsset(Asset asset) {
return Optional.ofNullable(asset)
.map(asset -> asset.getParents().iterator().next())
.orElseThrow(UnsupportedOperationException::new)
}
Otherwise if you'd like to return the optional, just remove the orElseThrow(). For each method of getParents(), iterator() or next(), which could possibly return null, you should create a map chain not to fall into a NPE. For example:
public Optional<NodeId> tmpFindParentNodeIdByAsset(Asset asset) {
return Optional.ofNullable(asset)
.map(asset -> asset.getParents())
.map(parents -> parents.iterator().next());
}
While I'm trying to use Optional features with method references, it really confused me how to optimize it with reusable code. I think I'm stuck while trying to use all those new features (for me) at the same time i decided to get rid of java-6 style, now I think i can't think simple, i feel that it gets overcomplicated. How can i create
List<BooleanExpression> expressionMapping = new ArrayList<>();
if (request != null) { // request is input parameter, a DTO
Optional.ofNullable(request.getPlantId())
.map(campaign.plant.id::contains) // campaign is static created by Querydsl
.ifPresent(expressionMapping::add);
Optional.ofNullable(request.getTitle())
.map(campaign.title::containsIgnoreCase)
.ifPresent(expressionMapping::add);
Optional.ofNullable(request.getCampaignNumber())
.map(this::getLikeWrapped)
.map(campaign.campaignNumber::like)
.ifPresent(expressionMapping::add);
... 20 more Optional bunch of code like this
}
also having trouble with writing this code with Optional like previous ones:
if (request.getLockVehicle() != null) {
if (request.getLockVehicle()) {
expressionMapping.add(campaign.lockVehicle.isNotNull());
} else {
expressionMapping.add(campaign.lockVehicle.isNull());
}
}
What about use enum to declare all fields from Request and use it as common part of the code. I did not check it, this is only to show my approach:
public enum RequestField {
PLANT_ID(Request::getPlantId, (val, campaign) -> campaign.plant.id::contains),
TITLE(Request::getTitle, (val, campaign) -> campaign.title::containsIgnoreCase),
CAMPAIGN_NUMBER(Request::getCampaignNumber, (val, campaign) -> campaign.campaignNumber::like),
// ... more fields here ...
;
private final Function<Request, Optional<Object>> get;
private final BiFunction<Object, Campaign, BooleanExpression> map;
RequestField(Function<Request, Object> get, BiFunction<Object, Campaign, BooleanExpression> map) {
this.get = get.andThen(Optional::ofNullable);
this.map = map;
}
public static List<BooleanExpression> getBooleanExpressions(Request request, Campaign campaign) {
if (request == null)
return Collections.emptyList();
List<BooleanExpression> res = new LinkedList<>();
for (RequestField field : values())
field.get.apply(request)
.map(r -> field.map.apply(r, campaign))
.ifPresent(res::add);
return res.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(res);
}
}
And your client code will be looking like:
List<BooleanExpression> booleanExpressions = RequestField.getBooleanExpressions(request, campaign);
P.S.
Your last code could be look like:
if (request.getLockVehicle() != null)
expressionMapping.add(request.getLockVehicle() ? campaign.lockVehicle.isNotNull() : campaign.lockVehicle.isNull());
The aim of using Optional is informing who is calling that method / parameter that it could be null.
In the first part of your code, you are not getting any advantage from this, you are just rewriting some code wrapping it around Optional logic but, as you said, without any "reusable" purpose.
A useful way is using it as returning value of a method: for example, if you know that your title could be null, you can refactor your getter like
public Optional<String> getTitle(){
return Optional.ofNullable(this.title); //I'm guessing the 'title' variable here
}
This will help you: every time you call getTitle() , you will know that could be null, because you are obtaining an Optional<String> instead of a String.
This will bring then you to:
request.getTitle().ifPresent(title-> title.doSomething())
// you can also add something like .orElse("anotherStringValue")
The second example could be reworked as the first one, making the return of getLockVehicle() as Optional<Boolean>, even if I suggest here setting that with a default value in your class, probably to false... Optional<Boolean> is pretty senseless imho
Hope this helps clearing your mind
This question already has answers here:
Null check chain vs catching NullPointerException
(19 answers)
Avoiding NullPointerException in Java
(66 answers)
Closed 4 years ago.
I need to check if some value is null or not. And if its not null then just set some variable to true. There is no else statement here. I got too many condition checks like this.
Is there any way to handle this null checks without checking all method return values?
if(country != null && country.getCity() != null && country.getCity().getSchool() != null && country.getCity().getSchool().getStudent() != null .....) {
isValid = true;
}
I thought about directly checking variable and ignoring NullpointerException. Is this a good practice?
try{
if(country.getCity().getSchool().getStudent().getInfo().... != null)
} catch(NullPointerException ex){
//dont do anything.
}
No, it is generally not good practice in Java to catch a NPE instead of null-checking your references.
You can use Optional for this kind of thing if you prefer:
if (Optional.ofNullable(country)
.map(Country::getCity)
.map(City::getSchool)
.map(School::getStudent)
.isPresent()) {
isValid = true;
}
or simply
boolean isValid = Optional.ofNullable(country)
.map(Country::getCity)
.map(City::getSchool)
.map(School::getStudent)
.isPresent();
if that is all that isValid is supposed to be checking.
You could use Optional here, but it creates one Optional object at each step.
boolean isValid = Optional.ofNullable(country)
.map(country -> country.getCity()) //Or use method reference Country::getCity
.map(city -> city.getSchool())
.map(school -> school.getStudent())
.map(student -> true)
.orElse(false);
//OR
boolean isValid = Optional.ofNullable(country)
.map(..)
....
.isPresent();
The object-oriented approach is to put the isValid method in Country and the other classes. It does not reduce the amount of null checks, but each method only has one and you don't repeat them.
public boolean isValid() {
return city != null && city.isValid();
}
This has the assumption that validation is the same everywhere your Country is used, but typically that is the case. If not, the method should be named hasStudent(), but this is less general and you run the risk of duplicating the whole School interface in Country. For example, in another place you may need hasTeacher() or hasCourse().
Another approach is to use null objects:
public class Country {
public static final Country NO_COUNTRY = new Country();
private City city = City.NO_CITY;
// etc.
}
I'm not sure it is preferable is this case (strictly you would need a sub class to override all modification methods), the Java 8 way would be to go with Optional as method in the other answers, but I would suggest to embrace it more fully:
private Optional<City> city = Optional.ofNullable(city);
public Optional<City> getCity() {
return city;
}
Both for null objects and Nullable only work if you always use them instead of null (notice the field initialization), otherwise you still need the null checks. So this option avoid null, but you code becomes more verbose to reduced null checks in other places.
Of course, the correct design may be to use Collections where possible (instead of Optional). A Country has a set of City, City has a set of Schools, which has set of students, etc.
As alternative to other fine usage of Optional, we could also use a utility method with a Supplier<Object> var-args as parameter.
It makes sense as we don't have many nested levels in the object to check but many fields to check.
Besides, it may easily be modified to log/handle something as a null is detected.
boolean isValid = isValid(() -> address, // first level
() -> address.getCity(), // second level
() -> address.getCountry(),// second level
() -> address.getStreet(), // second level
() -> address.getZip(), // second level
() -> address.getCountry() // third level
.getISO()
#SafeVarargs
public static boolean isValid(Supplier<Object>... suppliers) {
for (Supplier<Object> supplier : suppliers) {
if (Objects.isNull(supplier.get())) {
// log, handle specific thing if required
return false;
}
}
return true;
}
Suppose you would like to add some traces, you could so write :
boolean isValid = isValid( Arrays.asList("address", "city", "country",
"street", "zip", "Country ISO"),
() -> address, // first level
() -> address.getCity(), // second level
() -> address.getCountry(),// second level
() -> address.getStreet(), // second level
() -> address.getZip(), // second level
() -> address.getCountry() // third level
.getISO()
);
#SafeVarargs
public static boolean isValid(List<String> fieldNames, Supplier<Object>... suppliers) {
if (fieldNames.size() != suppliers.length){
throw new IllegalArgumentException("...");
}
for (int i = 0; i < suppliers.length; i++) {
if (Objects.isNull(suppliers.get(i).get())) {
LOGGER.info( fieldNames.get(i) + " is null");
return false;
}
}
return true;
}
Java doesn't have "null-safe" operations, like, for example Kotlin's null safety
You can either:
catch the NPE and ignore it
check all the references manually
use Optional as per the other answers
use some sort of tooling like XLST
Otherwise if you have control over the domain objects, you can redesign your classes so that the information you need is available from the top level object (make Country class do all the null checking...)
You could also look at vavr's Option which as the below posts describes is better than Java's Optional and has a much richer API.
https://softwaremill.com/do-we-have-better-option-here/
I have made a simple method in Java and I have a major error telling me that "Assigning an Object to null is a code smell. Consider refactoring.". Thus I should consider refactoring my code, but I am not sure I can find a way to re-write my sample of code differently.
Here is the code :
public static Key buildKey(TypeA a, TypeB b) {
Date myDate = new JavaDateUtcIsoStringDateConverter().from(String.valueOf(a.getDate));
Integer DateInt = new JavaDateUtcAvroIntDateConverter().to(myDate);
TypeNb nb = b.getById(a.getNbId());
Key.Builder builder = Key.newBuilder();
builder.setOr(a.getOr());
builder.setDest(a.getDest());
builder.setDateInt(DateInt);
builder.setLine(nb.getLine());
builder.setIdNb(nb.getIdNb());
builder.setOpS(nb.getOps() != null && String.valueOf(nb.getOps()).length() > 0 ? String.valueOf(nb.getOps()) : null);
return builder.build();
}
The main error comes from the line builder.setOpS(nb.getOps() != null && String.valueOf(nb.getOps()).length() > 0 ? String.valueOf(nb.getOps()) : null);
How can I refactor this simple condition in order to avoid using null ?
Any suggestions ?
Thanks
I suppose you could do something like:
if(nb.getOps() != null && String.valueOf(nb.getOps()).length() > 0) {
builder.setOpS(String.valueOf(nb.getOps());
}
... assuming you don't need to explicitly set the builder's value as null if nb.getOps() is empty.
If u don't want to use null pointers you should take a look at optional in Java 8 or GUAVA.
explanation
In builder pattern , avoid setting anything explicitly to null. If you want to set something to null, don't call the setter.
Also, keep it simple. You can use Apache commons-lang's StringUtils utility class for String not-null & not-empty
if (StringUtils.isNotBlank(nb.getOps())) {
builder.setOpS(String.valueOf(nb.getOps());
}
I'm trying to print a Date, just the way DateFormat.getDateTimeInstance() does it.
format throws a NullPointerException when passing null, so I've been wondering if there is a different approach that would return null (or "null") instead?
Something I'd call instead of
Date d = null;
System.out.println(d==null ? null : DateFormat.getDateTimeInstance().format(d));
You could just wrap the call inside a utility method :
public class DateUtils {
public static String formatDateTime(Date dateOrNull) {
return (dateOrNull == null ? null : DateFormat.getDateTimeInstance().format(dateOrNull));
}
}
private constructor and javadoc omitted for brevity.
What's the problem with your existing code?
null is kind of a special case, and you've decided that you want one particular behaviour in this case (returning "null") instead of another particular behaviour (throwing an NPE). It's arguably cleaner to express this via switching at the top level rather than burying this logic within the formatting method.
It might be a little cleaner to use a full if-else rather than a tertiary operator, though, to make it clearer that there are two distinct branches (normal, and special-cased null):
if (d == null) {
return "null"; // or whatever special case
}
else {
return DateFormat.getDateTimeInstance().format(d);
}
The return value in the null case should be made clear in your method's javadocs, too.