Preface:

Thank you for watching this article and I hope you all found it enjoyable

Introduction:

I have been working for 8 years since I graduated. I almost forget the year I graduated. I’ve been working on Java since I was a Java programmer, and now I finally have the time to sit down and write an article about Java writing, asking if you really know how to write Java if you are a Java programmer.

The author is a pragmatic programmer, so this article is not bullshit article, the contents of the article are dry goods, hope readers look, can have harvest.

This article is not a boast article, it will not talk about a lot of deep architecture, on the contrary, it will explain a lot of basic problems and writing problems, if the reader thinks that the basic problems and writing problems are not a problem, please ignore this article, save time to do something meaningful.

The development tools

It’s hard to know how many “older” programmers still use Eclipse, who are either stuck in the old ways or simply don’t know that other good development tools exist, but Eclipse’s memory lag and the odd aberration that comes along tells us it’s time to look for new tools.

Replace the IDE

I don’t even want to explain what IDE to switch to. If you want to be a good Java programmer, switch to IntelliJ IDEA. For the benefits of using IDEA, please search Google.

Don’t tell me shortcuts don’t work

Replacing an IDE is not the focus of this article, so I don’t want to spend too much time on why. Here, I can only tell you that the only reason to change ides is to write Java code better and faster. The reason is slightly.

Don’t tell me shortcuts don’t work. Try something new.

bean

Beans are one of our most used models, and I’ll cover beans at length in the hope that the reader gets a good feel for it.

Domain package name

According to the “experience” of many Java programmers, a database table corresponds to a domain object, so many programmers write code, the package name is: com.xxx.domain, such writing seems to have become a constraint of the industry, database mapping object should be domain. But you’re wrong, domain is a domain object, and often when we do traditional Java software Web development, these domains are anaemic models, they don’t have behavior, or they don’t have enough behavior of domain model, so in this theory, Each of these domains should be a generic Entity object, not a domain object, so change the package name to :com.xxx.entity.

If you don’t understand what I’m saying, take a look at a book called IMPLEMENTING Domain-Driven DESIGN by Vaughn Vernon, which explains the difference between an anaemic model and a DOMAIN model.

DTO

Data transmission we should use DTO objects as the transmission object, this is our agreement, because I have been doing mobile API design work for a long time, many people tell me that they think only when transmitting data to mobile phone (input or output), these objects become DTO objects. Please pay attention! Such understanding is wrong. As long as the objects are used for network transmission, we all think they can be regarded as DTO objects. For example, in the e-commerce platform, when users place an order, the data after placing an order will be sent to OMS or ERP system.

We agree to change the name of an object to XXDTO if it is a DTO object, such as OMSOrderInputDTO.

DTO transformation

As we know, Dtos are model objects for the system to interact with the outside world, so there must be a step to convert DTOS into BO objects or ordinary Entity objects for the Service layer to handle.

scenario

Operations such as adding members, because for demonstration, I only consider the user’s some simple data, when the background administrator click add user, only need to get the user’s name and age, the back-end, after receive the data will be added to create and update time and the default password three fields, then save the database.

@RequestMapping("/v1/api/user")
@RestController
public class UserApi {

    @Autowired
    private UserService userService;

    @PostMapping
    public User addUser(UserInputDTO userInputDTO){
        User user = new User();
        user.setUsername(userInputDTO.getUsername());
        user.setAge(userInputDTO.getAge());

        returnuserService.addUser(user); }}Copy the code

Let’s just focus on the transformation code in the above code, ignore the rest:

User user = new User();
user.setUsername(userInputDTO.getUsername());
user.setAge(userInputDTO.getAge());Copy the code

Please use tools

The above code, logically speaking, is fine, but it’s just annoying me to write it this way, so there are only two fields in the example, if there are 20 fields, what do we do? Do you set data one by one? Of course, if you do this, you’ll be fine, but it’s certainly not optimal.

There are many tools on the web that support shallow copy or deep copy Utils. For example, we can use the org. Springframework. Beans. BeanUtils# copyProperties for code refactoring and optimization:

@PostMapping
public User addUser(UserInputDTO userInputDTO){
    User user = new User();
    BeanUtils.copyProperties(userInputDTO,user);

    return userService.addUser(user);
}Copy the code

Beanutils.copyproperties is a shallow copy method. To copyProperties, we just need to set the DTO object and the converted object to the same name and ensure the same type. If you’re always using set for attribute assignments while doing DTO conversions, try simplifying your code and making it cleaner!

Semantics of transformation

The above conversion process, the reader will certainly feel a lot of elegant, but when we write Java code, we need to consider more semantic operations, again look at the above code:

User user = new User();
BeanUtils.copyProperties(userInputDTO,user);Copy the code

Although this code simplifies and optimizes the code well, there are problems with its semantics. We need to implement a transformation process, so the code is changed as follows:

@PostMapping
 public User addUser(UserInputDTO userInputDTO){
         User user = convertFor(userInputDTO);

         return userService.addUser(user);
 }

 private User convertFor(UserInputDTO userInputDTO){

         User user = new User();
         BeanUtils.copyProperties(userInputDTO,user);
         return user;
 }Copy the code

This is a better way of writing semantics. Although it is more complicated, it is much more readable. When writing code, we should try to put the same semantic level into a method, for example:

User user = convertFor(userInputDTO);
return userService.addUser(user);Copy the code

Neither code exposes the implementation, but rather shows how to do a set of semantic operations at the same level within the same method, rather than exposing the implementation.

As mentioned above, it’s a way of refactoring, The reader can refer to Extract Method Refactoring in Martin Fowler’s Refactoring Imporving the Design of Existing Code.

Abstract Interface definition

When the DTO conversion of several apis is done in practice, we will find that there are many such operations, so we should define an interface, so that all such operations have rules.

If the interface is defined, then the semantics of the convertFor method will change and it will be an implementation class.

Take a look at the abstract interface:

public interface DTOConvert<S,T> {
    T convert(S s);
}Copy the code

Although this interface is very simple, it tells us one thing: to use generics, if you are a good Java programmer, make generics for the abstract interface you want to make.

Let’s look at the interface implementation:

public class UserInputDTOConvert implements DTOConvert { @Override public User convert(UserInputDTO userInputDTO) { User  user = new User(); BeanUtils.copyProperties(userInputDTO,user);returnuser; }}Copy the code

When we refactor this way, we find that the code is now so concise and so normative:

@RequestMapping("/v1/api/user")
@RestController
public class UserApi {

    @Autowired
    private UserService userService;

    @PostMapping
    public User addUser(UserInputDTO userInputDTO){
        User user = new UserInputDTOConvert().convert(userInputDTO);

        returnuserService.addUser(user); }}Copy the code

review code

If you’re a good Java programmer, I’m sure you’ve reviewed your code several times, as I have.

The problem is that you shouldn’t return the User entity directly, because if you do that, you’re exposing too much information about the entity. It’s not safe to return a value like that, so instead you should return a DTO object, We can call it UserOutputDTO:

@PostMapping
public UserOutputDTO addUser(UserInputDTO userInputDTO){
        User user = new UserInputDTOConvert().convert(userInputDTO);
        User saveUserResult = userService.addUser(user);
        UserOutputDTO result = new UserOutDTOConvert().convertToUser(saveUserResult);
        return result;
}Copy the code

So your API is more robust.

I don’t know if you notice any other problems after reading this code, but as a good Java programmer, take a look at the code we just abstracted:

User user = new UserInputDTOConvert().convert(userInputDTO);Copy the code

As you can see, there is no need for a new DTO transform object, and each DTO transform object is generated when it encounters a DTO transform. Therefore, we should consider whether we can aggregate this class and the DTO.

public class UserInputDTO {
private String username;
private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    public User convertToUser(){
        UserInputDTOConvert userInputDTOConvert = new UserInputDTOConvert();
        User convert = userInputDTOConvert.convert(this);
        return convert;
    }

    private static class UserInputDTOConvert implements DTOConvert<UserInputDTO,User> {
        @Override
        public User convert(UserInputDTO userInputDTO) {
            User user = new User();
            BeanUtils.copyProperties(userInputDTO,user);
            returnuser; }}}Copy the code

The conversion in the API is then performed by:

User user = new UserInputDTOConvert().convert(userInputDTO);
User saveUserResult = userService.addUser(user);Copy the code

Becomes:

User user = userInputDTO.convertToUser();
User saveUserResult = userService.addUser(user);Copy the code

We added the transformation behavior to the DTO object, which I believe makes the code more readable and semantically correct.

Look again at the utility class

Looking at the DTO internal conversion code, it implements our own DTOConvert interface, but is there really no problem, no need to think about it?

I don’t think so. For conversion semantics like Convert, many utility classes have this definition. Convert is not a business-level interface definition, but a generic interface definition for converting property values between ordinary beans. Therefore, we should read more code with Convert semantics.

I carefully read the source of GUAVA, found com.google.com mon. Base. The Convert such a definition:

public abstract class Converter<A, B> implements Function<A, B> {
    protected abstract B doForward(A a);
    protected abstract A doBackward(B b); //Copy the code

GUAVA can Convert both forward and reverse versions of the DTO.

private static class UserInputDTOConvert implements DTOConvert<UserInputDTO,User> {
        @Override
        public User convert(UserInputDTO userInputDTO) {
                User user = new User();
                BeanUtils.copyProperties(userInputDTO,user);
                returnuser; }}Copy the code

Revised:

private static class UserInputDTOConvert extends Converter<UserInputDTO, User> {
         @Override
         protected User doForward(UserInputDTO userInputDTO) {
                 User user = new User();
                 BeanUtils.copyProperties(userInputDTO,user);
                 return user;
         }

         @Override
         protected UserInputDTO doBackward(User user) {
                 UserInputDTO userInputDTO = new UserInputDTO();
                 BeanUtils.copyProperties(user,userInputDTO);
                 returnuserInputDTO; }}Copy the code

After looking at this part of the code, you might ask, what’s the use of reverse conversion? In fact, we have a lot of small business requirements, input and output parameters are the same, so we can easily convert, I mentioned above UserInputDTO and UserOutputDTO to UserDTO show you.

DTO:

public class UserDTO {
    private String username;
    private int age;

    public String getUsername() {
            return username;
    }

    public void setUsername(String username) {
            this.username = username;
    }

    public int getAge() {
            return age;
    }

    public void setAge(int age) {
            this.age = age;
    }


    public User convertToUser(){
            UserDTOConvert userDTOConvert = new UserDTOConvert();
            User convert = userDTOConvert.convert(this);
            return convert;
    }

    public UserDTO convertFor(User user){
            UserDTOConvert userDTOConvert = new UserDTOConvert();
            UserDTO convert = userDTOConvert.reverse().convert(user);
            return convert;
    }

    private static class UserDTOConvert extends Converter<UserDTO, User> {
            @Override
            protected User doForward(UserDTO userDTO) {
                    User user = new User();
                    BeanUtils.copyProperties(userDTO,user);
                    return user;
            }

            @Override
            protected UserDTO doBackward(User user) {
                    UserDTO userDTO = new UserDTO();
                    BeanUtils.copyProperties(user,userDTO);
                    returnuserDTO; }}}Copy the code

API:

@PostMapping
 public UserDTO addUser(UserDTO userDTO){
         User user =  userDTO.convertToUser();
         User saveResultUser = userService.addUser(user);
         UserDTO result = userDTO.convertFor(saveResultUser);
         return result;
 }Copy the code

Of course, the above only indicates the forward or reverse direction of the transformation. Many business requirements have different Dtos for input and output parameters, so you need to tell the program more clearly: reverse cannot be called:

private static class UserDTOConvert extends Converter<UserDTO, User> {
         @Override
         protected User doForward(UserDTO userDTO) {
                 User user = new User();
                 BeanUtils.copyProperties(userDTO,user);
                 return user;
         }

         @Override
         protected UserDTO doBackward(User user) {
                 throw new AssertionError("Reverse conversion methods are not supported!"); }}Copy the code

Looking at the doBackward method, which throws an assertion exception directly, rather than a business exception, the code tells the caller of the code that the method is not yours to call, and if you call it, I “assert” that you called it incorrectly.

More detailed introduction about the exception handling, can refer to this article: how to elegant design Java exception (lrwinx. Making. IO / 2016/04/28 /…). That should help you understand anomalies better.

The bean validation

If you think the add user API I wrote above is perfect, you are not a good programmer. We should ensure that any data input into the method body is legal.

Why validate

A lot of people will tell me that if these apis are provided to the front end to make calls, the front end will validate them, why do you validate them?

The answer is like this, I never trust anyone call me API or method, such as front-end validation fails, or some people through some special channel (such as Charles caught), data into directly to my API, that I was still in the business logic of the normal processing, so it is possible to produce dirty data!

Keep in mind that “dirty data is fatal”. Even the smallest amount of dirty data can cause you to stay up all night!

JSR 303 validation

Hibernate provides the JSR 303 implementation, which I think is still very good. I don’t want to tell you how to use it, because you can find a lot of answers on Google!

To illustrate, we now check the DTO data:

public class UserDTO { @NotNull private String username; @NotNull private int age; // Other code omitted}Copy the code

API authentication:

@PostMapping
    public UserDTO addUser(@Valid UserDTO userDTO){
            User user =  userDTO.convertToUser();
            User saveResultUser = userService.addUser(user);
            UserDTO result = userDTO.convertFor(saveResultUser);
            return result;
    }Copy the code

We need to pass the validation results to the front end, and this exception should be converted into an API exception (with an error code).

@PostMapping public UserDTO addUser(@Valid UserDTO userDTO, BindingResult bindingResult){ checkDTOParams(bindingResult);  User user = userDTO.convertToUser(); User saveResultUser = userService.addUser(user); UserDTO result = userDTO.convertFor(saveResultUser);return result;
}
private void checkDTOParams(BindingResult bindingResult){
     if(bindingresult.haserrors ()){//throw new validation error exception with verification code}}Copy the code

The BindingResult is a result set after Spring MVC validates the DTO. You can refer to the official Spring documentation (spring.io/).

After checking the parameters, you can throw a validation error exception with a captcha

Specific can refer to this: very excellent article

http://lrwinx.github.io/2016/04/28/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E8%AE%BE%E8%AE%A1java%E5%BC%82%E5%B8%B8 /

Embrace the lombok

I’m tired of looking at this DTO code, and I’m sure the reader is tired of looking at all these getters and setters, so what’s the best way to simplify this?

Embrace Lombok and he will help us solve some of our most annoying problems

Get rid of setters and getters

In fact, I don’t want to say lombok because there are so many people online, but because many people tell me they don’t even know lombok exists, I’d like to write an example to make it easier for readers:

@Setter
@Getter
public class UserDTO {
    @NotNull
    private String username;
    @NotNull
    private int age;

    public User convertToUser(){
        UserDTOConvert userDTOConvert = new UserDTOConvert();
        User convert = userDTOConvert.convert(this);
        return convert;
    }

    public UserDTO convertFor(User user){
        UserDTOConvert userDTOConvert = new UserDTOConvert();
        UserDTO convert = userDTOConvert.reverse().convert(user);
        return convert;
    }

    private static class UserDTOConvert extends Converter<UserDTO, User> {
        @Override
        protected User doForward(UserDTO userDTO) {
            User user = new User();
            BeanUtils.copyProperties(userDTO,user);
            return user;
        }

        @Override
        protected UserDTO doBackward(User user) {
            throw new AssertionError("Reverse conversion methods are not supported!"); }}}Copy the code

You can see, the annoying getters and setters are gone.

But the above example is simply not enough to show lombok’s power. I wanted to write about the use of Lombok that is hard to find on the web, or rarely explained, and about the semantics of the program when it is used.

Such as: @ Data, @ AllArgsConstructor, @ NoArgsConstructor.. These I will not carry on a description, please inquire information by yourself.

Chain style in beans

What is chain style? For example, look at the following Student bean:

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public Student setName(String name) {
        this.name = name;
        return this;
    }

    public int getAge() {
        return age;
    }

    public Student setAge(int age) {
        returnthis; }}Copy the code

Take a closer look at the set method. This setting is the chain style. When called, it can be used like this:

Student student = new Student()
        .setAge(24)
        .setName("zs");Copy the code

If lombok is used properly, use @accessors (chain = true) to improve readability.

@Accessors(chain = true)
@Setter
@Getter
public class Student {
    private String name;
    private int age;
}Copy the code

This completes a bean-friendly chain operation.

Static constructor

Static constructors are really more semantic and simpler than just new an object. For example, new a List object, used like this:

List<String> list = new ArrayList<>();Copy the code

Take a look at the creation in Guava:

List<String> list = Lists.newArrayList();Copy the code

Lists naming is a convention (as the saying goes: Lists are a utility class of List. Is it more straightforward to use List’s utility class to generate Lists than to create a new subclass? Have you figured out a way to create a Map?

HashMap<String, String> objectObjectHashMap = Maps.newHashMap();Copy the code

Well, if you understand the semantics I’m talking about, then you’re one step closer to becoming a Java programmer.

Back to Student, a lot of times, when we write the Student bean, it will have some mandatory field, such as the name field in Student, and the general way to do that is to wrap the name field as a constructor, A Student object can only be created by passing in a constructor like name.

Using Lombok, add the above static constructor and the required constructor to the following (@requiredargsconstructor and @nonnull) :

@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = "ofName")
public class Student {
    @NonNull private String name;
    private int age;
}Copy the code

Test code:

Student student = Student.ofName("zs");Copy the code

Is the resulting bean semantic better than simply new a constructor with parameters (including the name constructor)?

Of course, after reading a lot of the source code, I’d like to believe that replacing the static constructor ofName with of would be much cleaner first:

@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = "of")
public class Student {
        @NonNull private String name;
        private int age;
}Copy the code

Test code:

Student student = Student.of("zs");Copy the code

Of course, he still supports chain calls:

Student student = Student.of("zs").setAge(24);Copy the code

It’s really neat and readable to write code like this.

Using a builder

Builder mode WITHOUT further explanation, the reader can take a look at The Builder mode in Head First.

Today we are going to talk about a variant of the Builder pattern, which is the Builder pattern for building beans. The main idea is to take you through what Lombok brings to the table.

Look at the original builder state of the Student class:

public class Student {
    private String name;
    private int age;

    public String getName() {
            return name;
    }

    public void setName(String name) {
            this.name = name;
    }

    public int getAge() {
            return age;
    }

    public void setAge(int age) {
            this.age = age;
    }

    public static Builder builder() {return new Builder();
    }
    public static class Builder{
            private String name;
            private int age;
            public Builder name(String name){
                    this.name = name;
                    return this;
            }

            public Builder age(int age){
                    this.age = age;
                    return this;
            }

            public Student build(){
                    Student student = new Student();
                    student.setAge(age);
                    student.setName(name);
                    returnstudent; }}}Copy the code

Call method:

Student student = Student.builder().name("zs").age(24).build();Copy the code

I was sick of the Builder code, so I decided to use Lombok to refactor it:

@Builder
public class Student {
    private String name;
    private int age;
}Copy the code

Call method:

Student student = Student.builder().name("zs").age(24).build();Copy the code

The proxy pattern

As we all know, invoking rest interfaces in programs is a common behavioral action, and if you’ve used Spring’s RestTemplate as I have, I’m sure you’ll find the non-HTTP status code exceptions it throws as distastefully as I do.

So let’s consider designing the RestTemplate wrapper for the lowest level wrapper pattern:

public abstract class FilterRestTemplate implements RestOperations { protected volatile RestTemplate restTemplate; protected FilterRestTemplate(RestTemplate restTemplate){ this.restTemplate = restTemplate; } // Implement all interfaces of RestOperations}Copy the code

The FilterRestTemplate is then wrapped and extended by the extension class:

public class ExtractRestTemplate extends FilterRestTemplate {
    private RestTemplate restTemplate;
    public ExtractRestTemplate(RestTemplate restTemplate) {
            super(restTemplate);
            this.restTemplate = restTemplate;
    }

    public <T> RestResponseDTO<T> postForEntityWithNoException(String url, Object request, Class<T> responseType, Object... uriVariables)
                    throws RestClientException {
            RestResponseDTO<T> restResponseDTO = new RestResponseDTO<T>();
            ResponseEntity<T> tResponseEntity;
            try {
                    tResponseEntity = restTemplate.postForEntity(url, request, responseType, uriVariables);
                    restResponseDTO.setData(tResponseEntity.getBody());
                    restResponseDTO.setMessage(tResponseEntity.getStatusCode().name());
                    restResponseDTO.setStatusCode(tResponseEntity.getStatusCodeValue());
            }catch (Exception e){
                    restResponseDTO.setStatusCode(RestResponseDTO.UNKNOWN_ERROR);
                    restResponseDTO.setMessage(e.getMessage());
                    restResponseDTO.setData(null);
            }
            returnrestResponseDTO; }}Copy the code

The ExtractRestTemplate wrapper nicely changes the exception throwing behavior to make the program more fault tolerant. Instead of thinking about the ExtractRestTemplate, let’s focus on the FilterRestTemplate, “Implement all interfaces to RestOperations.” This operation is by no means a write-off. I wrote for almost half an hour before refactoring, as follows:

public abstract class FilterRestTemplate implements RestOperations {

    protected volatile RestTemplate restTemplate;

    protected FilterRestTemplate(RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
    }

    @Override
    public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
            returnrestTemplate.getForObject(url,responseType,uriVariables); } @Override public <T> T getForObject(String url, Class<T> responseType, Map<String, ? > uriVariables) throws RestClientException {return restTemplate.getForObject(url,responseType,uriVariables);
    }

    @Override
    public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
            return restTemplate.getForObject(url,responseType);
    }

    @Override
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
            returnrestTemplate.getForEntity(url,responseType,uriVariables); } // Other implementation code is omitted... }Copy the code

I’m sure you’ll feel as sick to your stomach as I did when I optimized my code (@delegate) with lombok’s proxy annotations:

@AllArgsConstructor
public abstract class FilterRestTemplate implements RestOperations {
    @Delegate
    protected volatile RestTemplate restTemplate;
}Copy the code

These lines of code completely replace the verbose code above.

Isn’t it simple? Be a programmer who embraces Lombok.

refactoring

Demand case

The project requirements

In the development stage of the project, there is a demand for ordering and shipping: if the order is placed before 3pm today, the delivery time will be tomorrow; if the order is placed after 3pm today, the delivery time will be the day after tomorrow; if the confirmed time is Sunday, then one more day will be added to this time as the delivery time.

Thinking and reconstruction

I believe this requirement seems simple enough to accomplish no matter how it is written.

Many people might see this requirement and start writing Calendar or Date calculations to complete the requirement.

My advice is to think carefully about how to write code and then write it, not to use Calendar or Date for all time manipulation, but to depend on the scene.

For time calculation we should consider a similar mature time calculation framework such as Joda-time to write code, which makes the code more concise and readable.

Please consider how this requirement can be accomplished in Java code first, or write an idea of how you think this code can be accomplished, and then take a look at my code below, so that you can learn more:

Final DateTime DISTRIBUTION_TIME_SPLIT_TIME = new DateTime().withtime (15,0,0,0); private Date calculateDistributionTimeByOrderCreateTime(Date orderCreateTime){ DateTime orderCreateDateTime = new DateTime(orderCreateTime); Date tomorrow = orderCreateDateTime.plusDays(1).toDate(); Date theDayAfterTomorrow = orderCreateDateTime.plusDays(2).toDate();return orderCreateDateTime.isAfter(DISTRIBUTION_TIME_SPLIT_TIME) ? wrapDistributionTime(theDayAfterTomorrow) : wrapDistributionTime(tomorrow);
}
private Date wrapDistributionTime(Date distributionTime){
    DateTime currentDistributionDateTime = new DateTime(distributionTime);
    DateTime plusOneDay = currentDistributionDateTime.plusDays(1);
    boolean isSunday = (DateTimeConstants.SUNDAY == currentDistributionDateTime.getDayOfWeek());
    return isSunday ? plusOneDay.toDate() : currentDistributionDateTime.toDate() ;
}Copy the code

When you read this code, you will find that I treat the judgment and different possible results as a variable, and finally make a trinary operator to return, so elegant and readable is obvious, of course, this code is not overnight, I optimized the above code generated three times. Readers can compare their own code with the code I wrote.

Improve the method

If you’ve been a + programmer for 3 years, I’m sure you can easily do something like this, but if you want to be a Java programmer, think and refactor your code.

Writing code is like writing. People can write the same word, but it’s not always good. If you want to write a good program, you must constantly think and refactor, dare to try, dare to innovate, do not follow the conventional, must be a good Java programmer.

The best way to improve your code is to refactor it in an organized way! (Note: organized refactoring)

Design patterns

Design patterns are tools, not indicators of whether or not you are a good programmer.

I often see a programmer Shouting excitedly, which program I used the design pattern at which point, how good, how good. When I looked through it, I found a lot of it was over-engineered.

Service driven technologies or technologies drive services

Business Driving technology or technology driving business? Actually, this is an ongoing debate, but many people don’t think so. I think people just don’t want to admit it. Let me give you an overview of how we as Java programmers can judge where we stand.

Business-driven technology: If you’re working on a project with little or no revenue, don’t do something innovative, don’t drive the business how, but understand what the pain points of the business are right now. How to help the business make money or make the project better and smoother.

Technology-driven business: If your project is a very cow, such as taobao, this kind of project, I can meet the needs of the business, and business communication, use what kind of technology can better help business to create profits, such as order will go into the queue, may order status after a few minutes to complete the processing, but will allow the user to have a smooth experience, To earn more traffic, I believe that the business is willing to be technology-driven and will agree to delay orders, so that is technology-driven business.

I’m sure most people are still in the business-driven technology direction.

So if you can’t drive business, embrace business change.

Code design

I’ve been working on the Java back end, and there’s been a lot of change, as I’m sure you’ve all experienced.

For example, when we write a piece of code, we think about mapping the requirements to the code’s state pattern, and then one day, the state pattern adds a lot of behavior changes, and then you’re left scratching your head. You just add too many behaviors and changes to the state pattern.

Over time, you’ll realize that these state patterns are actually more like clusters of algorithms, and that you should be using strategy patterns, by which time you’ll have lost your head.

All I’m saying is, change the state mode to the policy mode whenever it makes sense to you. All modes are not imaginary, they are based on refactoring.

There is no silver bullet in Java programming, embrace business change, always think about refactoring, and you’ll have a better code design!

Are you really good?

I’m sorry I chose such a boring title.

There is a popular way of programming in foreign countries, called pair programming. I believe that many domestic companies do not do this, so I will not talk about the benefits of pair programming. In fact, it is a process of code review and mutual improvement. If you can’t do that, how do you keep improving in your own world?

“When you’re developing, you always make code that you think is right, and it’s written perfectly.” “, I believe this is the voice of most people. Back to the question, how do you improve in your own world?

The answer is:

  1. Read the source code of mature frameworks
  2. Look back at your code
  3. Diligent about refactoring

Are you really good? If you’ve done the work of learning source code every week, looking back at your own code, and refactoring diligently, I think you’re really good.

Even if you’re just getting started, stick with it and you’re a real Java programmer.

skills

UML

I don’t want to talk too much about UML, but I think if you really know how to write Java, learn to express yourself first. UML is the language you speak. To be a good Java programmer, learn at least two UML diagrams:

  1. The class diagram
  2. Sequence diagram

clean code

In my opinion, keeping code concise and readable is the most basic guarantee of code, and I think it is forgivable if these two things are compromised for the sake of program efficiency. Besides, there is no excuse for squandering your code.

  1. Check out Clean Code by Robert C. Martin
  2. Check out meituan’s article about Clean Code (tech.meituan.com/clean-code….). ;
  3. Can also take a look at ali’s Java coding standards (yq.aliyun.com/articles/69…). .

No matter what, keep your code clean.

Linux Basic Commands

This has nothing to do with being able to write Java, but Linux does host containers that run Java a lot of the time. Learn the basics of Linux commands.

  1. Refer to Birdman’s “Linux Home Dishes”

conclusion

Java is a big system, and today’s discussion is not about frameworks and architecture, just how to write good code.

This article explains how to write a good Java program from the small aspects all the way to the big aspects, and tells readers how to improve their coding level.

I hope everyone reading this becomes a good Java programmer

The last

Welcome to pay attention to my public number [Java small melon brother sharing platform], the article will be updated in it, sorting out the data will be placed in it