java
49 lines · 8 steps
Sorting Java imports with a regex pass
A single scan collects, dedupes, and sorts import statements, then splices a clean block back into the source.
Explained by
highlit
1public final class ImportOrganizer {
2
3 private static final Pattern IMPORT_LINE =
4 Pattern.compile("^import\\s+(static\\s+)?([\\w.]+(?:\\.\\*)?)\\s*;\\s*$");
5
6 public String organize(String source) {
7 List<String> lines = source.lines().collect(Collectors.toList());
8
9 SortedSet<String> staticImports = new TreeSet<>();
10 SortedSet<String> normalImports = new TreeSet<>();
11
12 int firstImport = -1;
13 int lastImport = -1;
14
15 for (int i = 0; i < lines.size(); i++) {
16 Matcher m = IMPORT_LINE.matcher(lines.get(i));
17 if (!m.matches()) {
18 continue;
19 }
20 if (firstImport < 0) {
21 firstImport = i;
22 }
23 lastImport = i;
24
25 if (m.group(1) != null) {
26 staticImports.add(m.group(2));
27 } else {
28 normalImports.add(m.group(2));
29 }
30 }
31
32 if (firstImport < 0) {
33 return source;
34 }
35
36 List<String> block = new ArrayList<>();
37 staticImports.forEach(fqn -> block.add("import static " + fqn + ";"));
38 if (!staticImports.isEmpty() && !normalImports.isEmpty()) {
39 block.add("");
40 }
41 normalImports.forEach(fqn -> block.add("import " + fqn + ";"));
42
43 List<String> result = new ArrayList<>(lines.subList(0, firstImport));
44 result.addAll(block);
45 result.addAll(lines.subList(lastImport + 1, lines.size()));
46
47 return String.join(System.lineSeparator(), result) + System.lineSeparator();
48 }
49}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A TreeSet gives you sorted, deduplicated output for free while you scan.
- 2Tracking first and last match indices lets you replace a contiguous region without re-parsing.
- 3A capturing group can classify a match (static vs normal) in the same pass that extracts it.
Related explainers
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
java
public static Map<String, String> parseCookieHeader(String header) { Map<String, String> cookies = new LinkedHashMap<>(); if (header == null || header.isBlank()) { return cookies;
Parsing an HTTP Cookie header in Java
string-parsing
http
url-decoding
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/sorting-java-imports-with-a-regex-pass-explained-java-bd8f/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.