Tips & Tricks

Code Formatting

The format of code is something all developers have an opinion on! With IntelliJ IDEA, a team can define their standards and have the IDE apply them automatically, so developers don’t have to think about formatting their code as they work.

This blog post covers the same material as the video. This provides an easy way for people to skim the content quickly if they prefer reading to watching, and to give the reader/watcher code samples and links to additional information.

Generally we’ll find while coding that we don’t need to manually format our code, IntelliJ IDEA does its best to do the right thing automatically. For example, if we press enter the caret goes into the correct place for us to start typing. The same applies if we use other shortcuts like ⇧⏎ to move to the next line, or use code generation.

Even if we take copy some code that is inconsistently formatted and paste it into the editor, IntelliJ IDEA will format this code to the project’s standards.

Reformatting Code

However, if we do have code that doesn’t meet the project’s standards, we can ask IntelliJ IDEA to format it.

    public void horriblyFormattedMethod  (){
        System.out.println("First line");
            System.out.println("Second line");
          System.out.println("Third line");
        for (int i = 0; i < 3; i++)
        System.out.println("I have no idea where the indentation is supposed to be");
    }

Highlight a specific piece of code, like the code above, and press ⌥⌘L, (Ctrl+Alt+L on Windows and Linux, but be aware that there are key conflicts with the operating system shortcuts on certain versions of Linux), to format just the highlighted code.  Or we can use this same shortcut without selecting the code and the whole file will be reformatted.  We also get a helpful balloon saying what the formatter did.

Screenshot of code after formatting

We can go into the preferences and set our expected standards.  In Editor -> Code Style -> Java (for our case), we’ll see all the formatting options.  We can duplicate the default code style settings and save them with a useful name.  When we change the settings, they will be saved to this scheme.

If we want to specify that if statements should always have curly braces, we go into Wrapping and Braces and force if statements to always have curly braces.  The preview on the right shows what selecting this setting will do to the code, so we can experiment with these settings to see which one we want.

If we save changes to the code style, when we format the code IntelliJ IDEA will reformat the code to the new style.

There are a lot of code style settings to potentially look through and change. There is a simpler way, if we have a section of code that we know needs reformatting differently.

    public void shouldForceCurlyBracesOnForLoops() {
        for (int i = 0; i < 3; i++)
            System.out.println("I have no idea where the indentation is supposed to be");
    }

For example, if we want for loops to also have curly braces, we can highlight an example of the code we want to change the formatting of, and press Alt+Enter.

Screenshot of the menu item for Adjust Code Style Settings

Then we select “Adjust code style settings”.  IntelliJ IDEA will show just the settings that apply to this bit of code. We can experiment with these settings and see the changes previewed live in our code. Under the “Wrapping and Braces” tab, under “‘for()’ statement” we can set “Force braces” to “true” always to have IntelliJ IDEA insert curly braces around the body of our for loop. When we save these changes, they will be saved to our current Code Style scheme.

Screenshot 2020-05-28 at 18.28.35

Often we don’t want to reformat the whole file that we’re working on, particularly if this is a system with inconsistent formatting and we don’t want to commit a lot of white space changes as well as our feature or bug fix.  If we were working on a file with some inconsistently formatted code, but we’ve only changed a small part of it, running “Reformat Code” might change parts of the file we haven’t touched. We could highlight the code we’ve changed and just reformat that, but that won’t work if our changes are scattered throughout the file.

There’s a better way: we can use ⌥⇧⌘L or Ctrl+Alt+Shift+L, to bring up the reformatting options.  We can say we only want to format the lines of the file that have been changed, and leave everything else alone.  Now when the file is formatted, it only changes the lines that we’ve touched and nothing else.

Example: Formatting Java 8 Streams

Let’s walk through setting specific formatting for use with Java 8 Streams. We’ll change the settings so that Stream operations are always on a separate line, and they are lined up underneath each other.

Let’s assume the current code style settings allow the chained method calls on the Streams API to stay on the same line, making an extremely long line of code.

private int replaceWithMapToInt() {
    int count = integerStringMap.values().stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(stringVal -> stringVal.contains("error")).mapToInt(String::length).sum();
    return count;
}

Highlight the stream all and use Alt+Enter to see which settings can be changed for this code.  Under the “Wrapping and Braces” tab, change the wrapping settings for “Chained method calls” to “Wrap always”.  We can try out these different settings to see which combination we want, the changes are previewed in the editor.

This is a good first step towards what we want, but we want the dots to all line up vertically.  To do this, we need to go into our code style settings.

Start typing the word “align” to search for it. Go to the “Wrapping and Braces” tab, and find “Chained method calls”.  This should already be set to “Wrap always” since we just set that.  We also need to tick “Align when multiline”. The preview should show us this is what we wanted. Save this change to the code style settings, and then reformat the file – the stream call should be aligned the way we wanted.

private int replaceWithMapToInt() {
    int count = integerStringMap.values()
                                .stream()
                                .filter(Objects::nonNull)
                                .flatMap(Collection::stream)
                                .filter(stringVal -> stringVal.contains("error"))
                                .mapToInt(String::length)
                                .sum();
    return count;
}

Using EditorConfig

These formatting settings are stored in a settings file in the project’s .idea folder. IntelliJ IDEA also supports using an EditorConfig file to define the code style. Create a new EditorConfig file in a package or directory. This will be our root, add the standard EditorConfig properties and IntelliJ IDEA-specific settings for Java code.

Screenshot of settings for editor config fileIntelliJ IDEA populates this file with all the settings that we’ve already defined for our code style. The properties are split into those which apply to all files, and those which apply only to Java files.  Anything with an “ij” prefix is a setting specific to IntelliJ IDEA.  If we look through all these settings, we can see the ones we’ve just defined for Java 8 streams: that we want chained method calls to be aligned; that we want chained method calls to be wrapped with one operation on each line.

ij_java_align_multiline_chained_methods = true
ij_java_method_call_chain_wrap = split_into_lines

Copy the Stream method call code and paste it into the preview panel for the editor config.  Then we can see what happens to our code when we make changes to the EditorConfig properties.

Screenshot of EditorConfig preview

(Note: for this screenshot I have removed all non-essential lines from under *.java)

Turn off the chained method calls wrapping by setting ij_java_method_call_chain_wrap to “off” (note that IntelliJ IDEA gives us code completion here). Set ij_java_keep_line_breaks to “false”. The preview shows us the Stream call is put back onto a single line.

If we go back to our code and reformat it, we can see IntelliJ IDEA uses the new EditorConfig settings to format the changed lines in the file. Note that our EditorConfig settings are used instead of the settings we defined in our Java Code Style preferences, which still has our old settings for Chained Method Calls. If we look at the Code Style Settings, we can see that EditorConfig support is enabled, and that this setting warns us the EditorConfig file settings may override the IDE settings.

Screenshot 2020-05-28 at 14.23.16

One of the advantages of using an EditorConfig file is that we can define a file for each directory. This is useful if we have different code settings for test code and production code, or if a legacy part of the code base has a different style.

IntelliJ IDEA supports it supports code completion for property names and values for the EditorConfig file, so we can use Ctrl+Space to bring up suggestions.  As usual, we can start typing something we’re looking for and the suggestions will be narrowed down.

IntelliJ IDEA offers even more help with EditorConfig files: for example, it can detect if a child config file contains duplicate settings to its parent, and we can get it to delete these duplicates too.

Screenshot 2020-05-28 at 14.25.08

Rearrange Code

We’ve seen how to reformat our code, how to change the settings for code style, including using an EditorConfig file to store the settings, and how reformatting can even do small code changes like adding braces.  Let’s look now at one of the options mentioned in the reformat file settings, Rearrange Code.

Open a class with a lot of methods and fields declared in it, like this one.

public class RearrangeCode {
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    private String firstName;

    public String getFirstName() {
        return firstName;
    }

    @Override
    public String toString() {
        return "RearrangeCode{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", middleName='" + middleName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", notes='" + notes + '\'' +
                ", ordersById=" + ordersById +
                '}';
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    private void privateHelperMethod() {
        // does something in here
    }

    private String middleName;

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    private String lastName;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    private String phone;

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    private String email;

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    private String notes;

    public String getNotes() {
        return notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RearrangeCode that = (RearrangeCode) o;
        return id == that.id &&
                Objects.equals(firstName, that.firstName) &&
                Objects.equals(middleName, that.middleName) &&
                Objects.equals(lastName, that.lastName) &&
                Objects.equals(phone, that.phone) &&
                Objects.equals(email, that.email) &&
                Objects.equals(notes, that.notes) &&
                Objects.equals(ordersById, that.ordersById);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, firstName, middleName, lastName, phone, email, notes, ordersById);
    }

    private Collection<Order> ordersById;

    public Collection<Order> getOrdersById() {
        return ordersById;
    }

    public void setOrdersById(Collection<Order> ordersById) {
        this.ordersById = ordersById;
    }
}

This class has fields, setters, getters, and other standard methods, all scattered throughout the file.  Use Find Action (⇧⌘A or Shift+Ctrl+A), and start typing “rearrange” to find the rearrange code action.  Select this and IntelliJ IDEA will reorder the code of this class according to the settings for the project.

public class RearrangeCode {
    private int id;
    private String firstName;
    private String middleName;
    private String lastName;
    private String phone;
    private String email;
    private String notes;
    private Collection<Order> ordersById;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @Override
    public String toString() {
        return "RearrangeCode{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", middleName='" + middleName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", notes='" + notes + '\'' +
                ", ordersById=" + ordersById +
                '}';
    }

    private void privateHelperMethod() {
        // does something in here
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getNotes() {
        return notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RearrangeCode that = (RearrangeCode) o;
        return id == that.id &&
                Objects.equals(firstName, that.firstName) &&
                Objects.equals(middleName, that.middleName) &&
                Objects.equals(lastName, that.lastName) &&
                Objects.equals(phone, that.phone) &&
                Objects.equals(email, that.email) &&
                Objects.equals(notes, that.notes) &&
                Objects.equals(ordersById, that.ordersById);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, firstName, middleName, lastName, phone, email, notes, ordersById);
    }

    public Collection<Order> getOrdersById() {
        return ordersById;
    }

    public void setOrdersById(Collection<Order> ordersById) {
        this.ordersById = ordersById;
    }
}

We can see all the fields are placed at the top of the file and the getters and setters for a field are placed next to each other.  This definitely helps to see at a glance what’s included in the state of an instance of this class.  However, we might want to go further in organising the code in a class.  For example, we might want to put private methods to the bottom of the class, underneath all the public ones.

Open up preferences/settings.  Once again, we need to be in Code Style -> Java, but this time we need to look under the Arrangement tab.  There are some standard rules which can be turned on or off, like keeping the getters and setters together.  The bottom section shows all the rules for arranging the file.  By default, fields will be ordered according to the modifiers that apply to them, and they’ll always be at the top of the file. Initialisers and constructors will come after the fields, methods come after that, and if there are any inner enums, interfaces or classes, they’ll be put at the bottom of the file.

Let’s change the existing method rule to apply to public methods, and add a new rule for methods that are private.

Screenshot of settings for arranging public methods above private methods

Note that these rules state the public methods should appear above the private methods.

We could use Find Action again to rearrange the file, or reformat the file and tick the rearrange code option. But we can also use Search Everywhere (shift shift) and type “rearrange”.  Once we’ve called the rearrange code action, we’ll see that our private method has been moved to the bottom of the file, underneath all the public methods.

public class RearrangeCode {
    private int id;
    private String firstName;
    private String middleName;
    private String lastName;
    private String phone;
    private String email;
    private String notes;
    private Collection<Order> ordersById;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @Override
    public String toString() {
        return "RearrangeCode{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", middleName='" + middleName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", notes='" + notes + '\'' +
                ", ordersById=" + ordersById +
                '}';
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getNotes() {
        return notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RearrangeCode that = (RearrangeCode) o;
        return id == that.id &&
                Objects.equals(firstName, that.firstName) &&
                Objects.equals(middleName, that.middleName) &&
                Objects.equals(lastName, that.lastName) &&
                Objects.equals(phone, that.phone) &&
                Objects.equals(email, that.email) &&
                Objects.equals(notes, that.notes) &&
                Objects.equals(ordersById, that.ordersById);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, firstName, middleName, lastName, phone, email, notes, ordersById);
    }

    public Collection<Order> getOrdersById() {
        return ordersById;
    }

    public void setOrdersById(Collection<Order> ordersById) {
        this.ordersById = ordersById;
    }

    private void privateHelperMethod() {
        // does something in here
    }
}

 

IntelliJ IDEA offers a lot of automation and configuration to let us define exactly how our files should be formatted, and we can even define the order things appear in our code files. This lets us define a consistent style for our project code, and encourages us to write code that’s consistent with the rest of our team.

See also:

image description