Get File Extension and MIME Type in Java Without Third-Party Libraries
You don’t need a third-party library to extract a filename’s extension or look up its MIME type in Java. The standard library covers both cases: Java 7’s NIO provides Files.probeContentType, and Java 8’s Optional lets you write the whole thing null-safe without much ceremony. Skipping the third-party dependency avoids a handful of real problems — extra runtime weight, API surface you never use, and the security exposure of an unmaintained library.
Get the file extension
The extension is whatever sits after the final . in a filename — usually a few letters or digits like .jpg, .mp3, .txt. Apache Commons IO’s FilenameUtils would handle this, but the goal here is code you can paste directly into any project with zero dependencies.
Simple approach
Two String methods are enough:
// Default to an empty string when no extension is present
String extension = "";
// The filename we're inspecting
String filename = "notes.txt";
// lastIndexOf returns -1 when the character isn't found
int idx = filename.lastIndexOf(".");
if (idx >= 0) {
// substring grabs everything after the dot — here: "txt"
extension = filename.substring(idx + 1);
}
lastIndexOf(".") is important: for a filename like report.tar.gz, only the final dot matters, so you get "gz" — not "tar.gz".
Clean it up with Optional
Wrapped in a utility class, the same logic fits in one expression and is null-safe by construction:
import java.util.Optional;
public class FileTools {
/**
* Return the extension of a filename, or a fallback if there isn't one.
*
* @param filename the filename to inspect; may be null
* @param orElse the fallback value; may be null
* @return the extension without the leading dot, or the fallback
*/
public static String getExtension(String filename, String orElse) {
return Optional.ofNullable(filename)
.filter(s -> s.contains("."))
.map(s -> s.substring(s.lastIndexOf(".") + 1))
.orElse(orElse);
}
}
Usage:
FileTools.getExtension("notes.txt", "");
// → "txt"
FileTools.getExtension("report.tar.gz", "");
// → "gz"
FileTools.getExtension(null, "");
// → ""
Detect the MIME type
Files.probeContentType (Java 7 NIO) will guess a MIME type from a filename. It’s worth knowing up front that Windows Explorer hides extensions by default and extensions are trivially changed, so an extension-based MIME type should be treated as a hint — not authoritative proof of what a file actually contains. For anything security-sensitive, sniff the file’s contents.
Path + Files
Build a Path from the filename, then let Files.probeContentType do the work. It returns null when no match is found and declares a checked IOException:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
String filename = "notes.txt";
// On Java 7–10 use Paths.get(filename); on Java 11+ you can write Path.of(filename)
Path path = Paths.get(filename);
String mime = Files.probeContentType(path);
// → "text/plain"
Paths.get() vs Path.of()
These two methods do exactly the same thing — turn a string into a Path. The difference is which class they live on. Paths.get() was added in Java 7 alongside NIO; at that point Path was an interface and interfaces couldn’t host static factory methods, so the utility class Paths held them instead. Java 8 relaxed that rule (static methods on interfaces), and Java 11 finally moved the factory onto Path itself as Path.of().
Since Java 11, Paths.get() is just a thin wrapper around Path.of() — the two are equivalent. For new code, prefer Path.of(): it matches the List.of() / Set.of() / Map.of() style introduced in Java 9, and you drop one import (Paths). If you’re stuck maintaining Java 8 code, Paths.get() is still your only option.
| Method | Class | Introduced in |
|---|---|---|
Paths.get() | java.nio.file.Paths | Java 7 |
Path.of() | java.nio.file.Path | Java 11 |
Cross-platform caveats
Files.probeContentType isn’t a pure-Java lookup — it delegates to the underlying OS:
- Linux reads
/etc/mime.types. - macOS has its own system mapping.
- Windows historically has a thin mapping and often returns
null, depending on the JDK vendor and version.
If you need consistent results across platforms, maintain your own extension-to-MIME-type lookup table. Doing it yourself also lets you decide the canonical MIME type for ambiguous cases (for example, .ts could be TypeScript, video/mp2t, or MPEG transport stream).
Clean it up with Optional (complete class)
Wrapping the call so callers don’t have to deal with IOException or a possible null:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
public class FileTools {
/**
* Return the MIME type guessed from a filename's extension, or a fallback.
*
* @param filename the filename to inspect; may be null
* @param orElse the fallback value; may be null
* @return the MIME type, or the fallback
*/
public static String getContentType(String filename, String orElse) {
return Optional.ofNullable(filename)
.map(s -> Paths.get(s))
.map(p -> {
try {
return Files.probeContentType(p);
} catch (IOException e) {
return null;
}
})
.orElse(orElse);
}
}
Usage:
FileTools.getContentType("notes.txt", "");
// → "text/plain"
With these two small helpers you can keep filename handling inside the standard library — no extra dependencies, no transitive vulnerabilities to worry about, and the code fits into a gist.