I’m Done for: IntelliJ IDEA’s Postfix Completion Feature

2021/03/04

Preface

Earlier I wrote a post introducing IDEA’s Live Templates (dynamic templates). Honestly, there’s way too much “reference material” online for this—everyone just copies everyone else, not even changing the formatting. If the formatting is different, it’s probably because they accidentally lost it while copy-pasting.

I’ve always had a need: I want var.sout + Enter to turn into System.out.println(var);. I’ve researched this multiple times. My original approach was wrong—I kept thinking this was a Live Templates feature, but Live Templates can’t put that var into println() while also keeping var in front. I always felt like there must be some built-in trick I didn’t know, so I even went through IDEA’s official docs, reread all the built-in functions for variables again and again, and studied how IDEA’s built-in sout works for a long time… and every time I ended up giving up.

Let me give a super simple example. I want to use a Live Template to write a .test that implements sout.

  1. First step: set up a Live Template

image-20210404183921703

Set up a test, and apply it to java-other
  1. Then look at the result

    2021-04-04 18.38.10

The result is pretty dumb

In the end, I found something in IDEA’s docs called Postfix Completion. I searched for it in IDEA and it scared me—turns out the .var / .sout I’d been dreaming about is right here!!!

image-20210404184658588

It includes most commonly used implementations

After tinkering with it for a while, I want to summarize what I’ve learned: some built-in postfix completions I use a lot, plus a few custom ones I made and want to share.

IDEA built-in postfix completions I use

  • Quickly generate a for loop — num.fori

    2021-04-04 19.00.47

  • Quick null check and non-null check — num.null & num.nn

2021-04-04 19.15.09

  • String format concatenation — string.format

2021-04-04 19.16.20

  • Quick new and quick reference generation — class.new & object.var

2021-04-04 19.17.40

  • Quickly wrap code with try/catch — statement.try

2021-04-04 19.18.32

  • Quick return — result.return

2021-04-04 19.19.03

You can probably tell this looks a lot like Live Templates. That’s exactly why I kept looking in the wrong direction before. This is basically Live Templates plus. Notice that most of the time I just type the first few letters and then use completion—once you get used to it, it feels so good, and your bug-producing efficiency goes up up 😜

Custom postfix completions

Explanation

Everything above is built into IDEA, but we can also write our own. It’s similar to Live Templates, except there’s no concept of groups here—custom ones all get written under Java. My OCD doesn’t love it, but if it boosts efficiency, I’ll live with it.

So how do you write one? The best way is to look at how IDEA’s built-in postfix completions are implemented. I’ll use the sout I’d been obsessing over as an example.

image-20210404192600733

The image above is the implementation of sout. Following the annotations in the screenshot, here’s what each part means:

  1. This is the key, i.e. .key, the trigger condition for your postfix completion
  2. Applicable JDK version. Some lambda syntax might only be supported in JDK 8, and you can configure that here
  3. Applicable types. Usually it’s fine whether you fill this in or not, but specifying it makes it more robust
  4. $EXPR$ means expr.key. This is where the expr will end up
  5. $END$ is where your cursor will land at the end

Sharing

First: I’m only sharing my ideas. I’m not going to export and share my exact configuration—not because I’m stingy, but because I grind away writing it for ages, and if I just hand it over, everyone’s creativity drops a bit.

  • Anyone who’s written Scala knows how nice toInt, toLong, etc. are for direct casting. But in Java you basically only have toString(), and I often don’t dare to use it casually because of NPE. Hutool has a static class Convert. Let’s just look at toStr:

image-20210404193838992

Introduction to Convert.toStr()

2021-04-04 19.41.40

My commonly used conversion demo
  • Collection null/empty checks. With MyBatis, if no data is found, the ORM returns null for objects, but for collections it returns an empty collection. If you check a collection for null, there’s a high chance it won’t match your expectations. Sure, collections have isEmpty() to quickly check whether there are elements, but relying on that habit isn’t very robust—what if one day the collection itself is null and the method doesn’t exist at all, boom NPE… Here’s my postfix approach:

    2021-04-04 19.52.08

Demo

Afterword

There’s actually a lot you can do with this. I really searched for a long time—turns out flipping through the manual more often always brings new discoveries. These days I basically treat IDEA’s manual as English reading material every day: first, it has tons of CS vocabulary, and memorizing more of it will definitely be useful later; second, I personally feel we still haven’t dug deep enough into IDEA. IDEA is powerful—not just something people hype up domestically. There are lots of efficiency-boosting tricks that only a few people might know, waiting for us to explore.

IDEA docs here: click

All articles in this blog, unless otherwise stated, are licensed under @Oreoft . Please indicate the source when reprinting!

Table of Contents