Some days Java feels like groundhog day. Copy a directory. Read a stream into a String. Check if a value is blank. Build a decent toString and equals without turning your class into a festival of boilerplate. Then you remember Apache Commons IO and Apache Commons Lang. These two sit in the toolbox and quietly make life better. With Java 7 feeling fresh and GitHub full of tiny helpers, Commons still earns a place in every project that ships.
Commons IO keeps file code clean
Start with FileUtils and IOUtils. They turn file and stream code into something you can read next week without a deep breath. A few hits I reach for all the time:
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.nio.charset.Charset;
// Copy a whole directory
File src = new File("/data/incoming");
File dst = new File("/data/processing");
FileUtils.copyDirectory(src, dst);
// Read a file as String with charset
String text = FileUtils.readFileToString(
new File("/data/config/app.conf"),
Charset.forName("UTF-8")
);
// Download a small file
FileUtils.copyURLToFile(
new URL("http://example.com/logo.png"),
new File("/tmp/logo.png"),
5000, // connect timeout
5000 // read timeout
);
// Stream to String the easy way
try (FileInputStream in = new FileInputStream("/tmp/data.json")) {
String json = IOUtils.toString(in, "UTF-8");
}There is also FilenameUtils for extensions and normalization, and FileFilterUtils for filters that do not look like spaghetti. If you have a command tool or an ETL task running at night, these helpers keep the code short and the intent clear.
Commons Lang for strings objects and sanity checks
Commons Lang is the friend you ping when java.lang gets a bit bare. Strings first, with StringUtils doing the boring bits without clutter:
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.ObjectUtils;
// String tricks
boolean ok = StringUtils.isNotBlank(userInput);
String safe = StringUtils.defaultString(maybeNull); // never NPE
String csv = StringUtils.join(new String[]{"a","b","c"}, ',');
// Quick sanity checks
Validate.notBlank(username, "username is required");
Validate.isTrue(age >= 18, "must be adult");
// Null safe defaults
String city = ObjectUtils.defaultIfNull(requestCity, "Unknown");For model classes, the builders keep your equals hashCode and toString short and tidy. You can still write them by hand if you feel like it, yet the builders avoid mistakes and make intent obvious.
public final class User {
private final String id;
private final String name;
public User(String id, String name) {
Validate.notBlank(id, "id");
Validate.notBlank(name, "name");
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.toString();
}
}Little patterns that save time
Two tips that keep popping up in real code:
- Always set a charset. With IOUtils and FileUtils, pass UTF 8 or what you need. Random defaults lead to bad nights.
- Prefer Validate at the edges. Throw early with a clear message. It pays for itself the first time a controller gets a null in prod.
// Line by line without surprises
import org.apache.commons.io.LineIterator;
try (LineIterator it = FileUtils.lineIterator(new File("events.log"), "UTF-8")) {
while (it.hasNext()) {
String line = it.nextLine();
if (StringUtils.startsWith(line, "WARN")) {
// handle
}
}
}There is also StopWatch for quick timing in Lang when you want a simple measure during a refactor or a production incident.
import org.apache.commons.lang3.time.StopWatch;
StopWatch sw = new StopWatch();
sw.start();
// do work
sw.stop();
System.out.println("Took " + sw.getTime() + " ms");Commons vs plain JDK grind
You can copy a stream with the JDK. It just reads like a chore. Compare both ways and see which one you want to read during a code review.
// JDK only
byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) != -1) {
out.write(buf, 0, n);
}
out.flush();// Commons IO
IOUtils.copy(in, out);
out.flush();Same with strings. Writing your own isBlank over and over makes bugs. StringUtils.isBlank just works and everyone on the team knows what it does.
Practical checklist
- Pick versions. For many teams right now, commons io 2.1 and commons lang3 3.1 are solid picks.
- Add to Maven and move on with life:
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.1</version> </dependency> - On Ivy or Ant. Grab the same artifacts from Maven Central. Keep them close to the build so new devs do not hunt jars.
- Set a tiny team rule. When you write file or string helpers, check Commons first. Less code to maintain is a win.
- Watch for quiet deletes. If you use deleteQuietly make sure the silence is intentional. Logs matter.
- Use Validate in public methods. Private code can skip some checks once your edges are strong.
- Run a quick grep. Find loops that copy streams and swap them with IOUtils.copy. Turn ten lines into one and move on.
- Adopt builders for models. EqualsBuilder HashCodeBuilder and ToStringBuilder keep the boring parts short and clear.
Search tip: queries like apache commons io FileUtils copyDirectory or apache commons lang StringUtils isBlank land you on short docs with plenty of examples. Stack Overflow is full of answers for edge cases too.
One last thought: these libs sit well with Eclipse Indigo and IntelliJ IDEA, autocompletion makes them feel native.
Small helpers big calm.