In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains "how to solve the Bug caused by null values in Java". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to solve the Bug caused by null values in Java".
Null value in the business
Scene
There is a function that UserSearchService uses to provide user queries:
Public interface UserSearchService {List listUser (); User get (Integer id);}
Problem scene
The level of abstraction is particularly important for object-oriented languages. In particular, the abstraction of the interface, which accounts for a large proportion in the design and development, we hope to be interface-oriented programming as far as possible.
From the interface method described above, it can probably be inferred that it contains the following two meanings:
ListUser (): query the list of users
Get (Integerid): query a single user
In all the development, the TDD pattern advocated by XP can well guide us to define the interface, so we use TDD as the "promoter" of the development code.
For the above interfaces, when we use TDD for test cases first, we find potential problems:
If listUser () has no data, does it return an empty collection or null?
If get (Integerid) does not have this object, will it throw an exception or return null?
In-depth listUser research
Let's discuss it first.
ListUser ()
For this interface, you can often see the following implementation:
Public List listUser () {List userList = userListRepostity.selectByExample (new UserExample ()); if (CollectionUtils.isEmpty (userList)) {/ / spring util utility class return null;} return userList;}
This code returns null, and from my years of development experience, it's best not to return null for collections like this, because if null is returned, it will cause a lot of trouble to the caller. You will leave this call risk to the caller.
If the caller is a cautious person, he will make a conditional judgment as to whether it is null or not. If he is not cautious, or he is a fanatic of interface-oriented programming (of course, interface-oriented programming is the right direction), he will call the interface according to his own understanding, instead of judging whether it is a null condition, if so, it is very dangerous, it is very likely to have a null pointer exception!
Based on this, we optimize it:
Public List listUser () {List userList = userListRepostity.selectByExample (new UserExample ()); if (CollectionUtils.isEmpty (userList)) {return Lists.newArrayList (); / / the way provided by the guava class library} return userList;}
For the interface (ListlistUser ()), it must return List, even if there is no data, it will still return List (there are no elements in the collection)
Through the above modifications, we have successfully avoided the possible null pointer exception, which is safer to write!
Deep study of get method
For interfac
User get (Integer id)
What you can see is that if I give id, it will definitely return User. But it is really possible that this is not the case.
The implementations I've seen:
Public User get (Integer id) {return userRepository.selectByPrimaryKey (id); / / get entity objects directly from the database via id}
I believe many people will write the same way.
When you go through the code, you know that its return value is most likely null! But the interface we pass through is indistinguishable!
This is a very dangerous thing. Especially for callers!
My suggestion is that you need to supplement the documentation when the interface is explicit, such as using the annotation @ exception for exception descriptions:
Public interface UserSearchService {/ * obtain user information according to user id * @ param id user id * @ return user entity * @ exception UserNotFoundException * / User get (Integer id);}
After we add a description to the interface definition, the caller will see that if the interface is called, it is likely to throw an exception such as "UserNotFoundException".
In this way, you can see the definition of the interface when the caller invokes the interface, but it is a "weak prompt"!
If the caller ignores comments, it may pose a risk to the business system, which may lead to 100 million!
In addition to the "weak prompt" approach above, another way is that the return value is likely to be empty. What are we going to do?
I think we need to add an interface to describe this scenario.
Introduce Optional of jdk8, or use Optional of guava. Look at the definition as follows:
Public interface UserSearchService {/ * obtain user information based on user id * @ param id user id * @ return user entity, which may be the default value * / Optional getOptional (Integer id);}
Optional has two meanings: there is an or default.
So by reading the interface getOptional (), we can quickly understand the intention of the return value, which is actually what we want to see, which removes ambiguity.
Its implementation can be written as follows:
Public Optional getOptional (Integer id) {return Optional.ofNullable (userRepository.selectByPrimaryKey (id));}
In-depth input parameter
Through the description of all the above interfaces, can you be sure that the input parameter id must be required? I think the answer should be: I'm not sure. Unless specified in the documentation notes for the interface.
Then how to restrict the entry of parameters?
Two ways are recommended:
Mandatory constraint
Documentation constraints (weak prompts)
1. To enforce constraints, we can make strict constraint declarations through jsr 303:
Public interface UserSearchService {/ * obtain user information based on user id * @ param id user id * @ return user entity * @ exception UserNotFoundException * / User get (@ NotNull Integer id) / * * obtain user information according to user id * @ param id user id * @ return user entity, which may be the default value * / Optional getOptional (@ NotNull Integer id);}
Of course, to write this way, it needs to be verified with the operation of AOP, but let spring already provide a good integration solution, so I won't repeat it here.
two。 Documentation constraint
In many cases, we will encounter legacy code, for legacy code, the possibility of overall transformation is very small.
We prefer to read the implementation of the interface to describe the interface.
The jsr305 specification gives us a way to describe the interface input parameters (need to import the library com.google.code.findbugs:jsr305):
You can use the annotation @ Nullable @ Nonnull @ CheckForNull to describe the interface. For example:
Public interface UserSearchService {/ * obtain user information based on user id * @ param id user id * @ return user entity * @ exception UserNotFoundException * / @ CheckForNull User get (@ NonNull Integer id) / * * obtain user information according to user id * @ param id user id * @ return user entity, which may be the default value * / Optional getOptional (@ NonNull Integer id);}
Summary
Through the empty collection return value, Optional,jsr 303 JSR 305 these ways, we can make our code more readable, lower error rate!
Empty collection return value: if a collection returns a value like this, be sure to return an empty collection, not null, unless you really have a reason to convince yourself.
Optional: if your code is jdk8, introduce it! If not, use Guava's Optional, or upgrade the jdk version! It can greatly increase the readability of the interface!
Jsr 303: if a new project is under development, add this! There must be a very cool feeling!
Jsr 305: if the old project is in your hands, you can try to add this kind of document comments to help you later refactoring, or new features have been added, the understanding of the old interface!
Null object mode
Scene
Let's take a look at a scene transformed by DTO, with objects:
@ Data static class PersonDTO {private String dtoName; private String dtoAge;} @ Data static class Person {private String name; private String age;}
The requirement is to convert the Person object to PersonDTO and then return it.
Of course, for the actual operation, if Person is empty, null will be returned, but PersonDTO cannot return null (especially the DTO returned by the Rest interface).
Here, we only focus on the conversion operation, and look at the following code:
@ Test public void shouldConvertDTO () {PersonDTO personDTO = new PersonDTO (); Person person = new Person (); if (! Objects.isNull (person)) {personDTO.setDtoAge (person.getAge ()); personDTO.setDtoName (person.getName ());} else {personDTO.setDtoAge ("); personDTO.setDtoName (");}}
Optimization and modification
The readability of such data conversion is very poor, and the judgment of each field is set to an empty string (") if it is empty.
To think in a different way of thinking, we get the data of the class Person and then setXXX it. It doesn't matter who the specific implementation of Person is.
Then we can create a Person subclass:
Static class NullPerson extends Person {@ Override public String getAge () {return ";} @ Override public String getName () {return";}}
It exists as a special case of Person and returns some default behavior of get* if Person is empty.
So the code can be changed to:
@ Test public void shouldConvertDTO () {PersonDTO personDTO = new PersonDTO (); Person person = getPerson (); personDTO.setDtoAge (person.getAge ()); personDTO.setDtoName (person.getName ());} private Person getPerson () {return new NullPerson (); / / if Person is null, return empty object}
The getPerson () method can be used to obtain Person possible objects according to the business logic (for the current example, if Person does not exist, return the special case NUllPerson of Person). If modified like this, the readability of the code will become very strong.
Optimization can be done with Optional
Empty object pattern, its disadvantage is that we need to create a special case object, but if there are more special cases, do we need to create multiple special case objects? although we also use the object-oriented polymorphic feature, if the complexity of the business really allows us to create multiple special case objects, we still have to think twice about this pattern, it may bring code complexity.
For the above code, you can also use Optional to optimize.
@ Test public void shouldConvertDTO () {PersonDTO personDTO = new PersonDTO (); Optional.ofNullable (getPerson ()) .ifPresent (person-> {personDTO.setDtoAge (person.getAge ()); personDTO.setDtoName (person.getName ());});} private Person getPerson () {return null;}
I think Optional's use of null values is more appropriate, and it only applies to "whether it exists" scenarios.
If you only judge the existence of control, I recommend using Optional.
The correct use of Optioanl
Optional is so powerful that it expresses the most primitive features of a computer (0 or 1), so how can it be used correctly?
Optional should not be used as a parameter
If you write a public method that specifies some input parameters, some of which can be passed into null, can you use Optional at this time?
The advice is: don't use it like this!
For example:
Public interface UserService {List listUser (Optional username);}
The method listUser of this example may tell us that we need to query all data sets according to username, and return all user sets if username is empty.
When we see this method, we will feel that there are some ambiguities:
"if username is absent, does it return an empty collection or the entire set of user data?"
Optioanl is a branch of judgment, so do we focus on Optional or Optional.get ()?
The advice to everyone is that if you don't want such ambiguity, don't use it!
If you really want to express two meanings, split it into two interfaces:
Public interface UserService {List listUser (String username); List listUser ();}
I think this is more semantic and better meets the "single responsibility" of software design principles.
If you think it is really necessary for your input parameter to send null, please use jsr 303 or jsr 305 for explanation and verification!
Please remember! Optional cannot be used as an input parameter!
Optional as the return value
When the return of an entity
Can Optioanl be used as a return value?
In fact, it is very satisfied with the existence of this semantics.
If you say that you want to get user information according to id, this user may or may not exist.
You can use it like this:
Public interface UserService {Optional get (Integer id);}
When calling this method, the caller knows very well that the data returned by the get method may not exist, which can make some more reasonable judgments and better prevent null pointer errors!
Of course, if the business side really needs to query User according to id, do not use it this way, please indicate the exception you want to throw.
The return of null is performed only if it is reasonable to consider that it returns Optional
Return of collection entity
Not all return values can be used in this way! If you return a collection:
Public interface UserService {Optional listUser ();}
Such a return result will make the caller at a loss. Do I have to make an isEmpty judgment after I judge Optional?
This brings the ambiguity of the return value! I don't think it's necessary.
We have to agree that for the return value of a collection such as List, if the collection is really null, please return an empty collection (Lists.newArrayList)
Use Optional variabl
Optional userOpt =...
If there is such a variable userOpt, remember:
You must not use get directly. If you do, you will lose the meaning of Optional itself (such as userOp.get ()).
Do not use getOrThrow directly, if you have such a requirement: throw an exception if you can't get it. Then we have to consider whether the calling interface is designed reasonably.
Use in getter
For a java bean, it is possible for all properties to return null, so do you need to rewrite all getter to Optional type?
The advice to everyone is, don't abuse Optional like this.
Even if the getter in my java bean conforms to Optional, because there are too many java bean, this will cause more than 50% of your code to be judged by Optinal, which will contaminate the code. (I would like to say that, in fact, the fields in your entity should all be business meaning, will seriously think about the value of its existence, and should not be abused because of the existence of Optional.)
We should pay more attention to the business, not just the judgment of null value.
Don't abuse Optional in getter.
Thank you for your reading, the above is the content of "how to solve the Bug caused by null values in Java". After the study of this article, I believe you have a deeper understanding of how to solve the problem of Bug caused by null values in Java, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.