Properties Class
The Properties class is Java’s built-in solution for managing key-value configuration data — think database URLs, API endpoints, or application settings stored in a simple .properties file. It extends Hashtable<Object, Object> and adds convenient methods for loading from and saving to streams, making it the standard way to externalize configuration in Java applications.
What is the Properties Class?
Properties lives in the java.util package. Every key and value is a String, even though it technically inherits from Hashtable<Object, Object>. This string-only convention is what makes .properties files so portable and easy to edit without touching code.
A typical .properties file looks like this:
# app.properties
db.url=jdbc:mysql://localhost:3306/mydb
db.user=admin
db.password=secret
app.name=MyApp
app.version=2.0
Lines starting with # or ! are comments. Keys and values are separated by = or :.
Creating a Properties Object
You can create a Properties object with or without default values:
import java.util.Properties;
public class CreateProperties {
public static void main(String[] args) {
// Empty properties
Properties props = new Properties();
// Set values manually
props.setProperty("app.name", "DevCraftly");
props.setProperty("app.version", "1.0");
// Retrieve a value
String name = props.getProperty("app.name");
System.out.println("App: " + name);
// Retrieve with a fallback default
String env = props.getProperty("app.env", "production");
System.out.println("Env: " + env);
}
}
Output:
App: DevCraftly
Env: production
Tip: Always use
getProperty(key, defaultValue)when a missing key should fall back gracefully instead of returningnull.
Loading Properties from a File
The most common use case is reading a .properties file from your classpath or filesystem.
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class LoadProperties {
public static void main(String[] args) throws IOException {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream("app.properties")) {
props.load(fis);
}
System.out.println("DB URL : " + props.getProperty("db.url"));
System.out.println("DB User: " + props.getProperty("db.user"));
}
}
Output:
DB URL : jdbc:mysql://localhost:3306/mydb
DB User: admin
Tip: In a Maven/Gradle project, place
app.propertiesinsidesrc/main/resources. Load it from the classpath usinggetClass().getResourceAsStream("/app.properties")so it works in JAR files too.
Loading from the Classpath
import java.io.InputStream;
import java.io.IOException;
import java.util.Properties;
public class ClasspathProperties {
public static void main(String[] args) throws IOException {
Properties props = new Properties();
try (InputStream is = ClasspathProperties.class
.getResourceAsStream("/app.properties")) {
if (is == null) {
throw new IOException("app.properties not found on classpath");
}
props.load(is);
}
System.out.println(props.getProperty("app.name"));
}
}
Saving Properties to a File
You can persist a Properties object back to disk using store():
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class SaveProperties {
public static void main(String[] args) throws IOException {
Properties props = new Properties();
props.setProperty("theme", "dark");
props.setProperty("language", "en");
try (FileOutputStream fos = new FileOutputStream("user.properties")) {
props.store(fos, "User Preferences");
}
System.out.println("Saved successfully.");
}
}
This writes a file like:
#User Preferences
#Fri Jun 13 10:00:00 UTC 2026
theme=dark
language=en
Note: The order of keys in the saved file is not guaranteed because
Propertiesinherits the unordered nature ofHashtable. If you need sorted output, iterate over aTreeSetof the property names.
XML Format
Properties also supports XML via loadFromXML() and storeToXML():
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class XmlProperties {
public static void main(String[] args) throws IOException {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream("config.xml")) {
props.loadFromXML(fis);
}
props.forEach((k, v) -> System.out.println(k + " = " + v));
}
}
The XML format looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="db.url">jdbc:mysql://localhost/mydb</entry>
<entry key="db.user">admin</entry>
</properties>
Iterating Over All Properties
You have a few options to loop through all entries:
import java.util.Properties;
public class IterateProperties {
public static void main(String[] args) {
Properties props = new Properties();
props.setProperty("host", "localhost");
props.setProperty("port", "8080");
props.setProperty("debug", "true");
// Option 1: stringPropertyNames() — only String keys
for (String key : props.stringPropertyNames()) {
System.out.println(key + " = " + props.getProperty(key));
}
// Option 2: forEach (lambda)
System.out.println("--- forEach ---");
props.forEach((k, v) -> System.out.println(k + " -> " + v));
}
}
Output:
host = localhost
port = 8080
debug = true
--- forEach ---
host -> localhost
port -> 8080
debug -> true
Tip: Prefer
stringPropertyNames()overkeySet()when you only care aboutStringkeys — it filters out any non-string keys that may have been added through the inheritedHashtableAPI.
System Properties
Java exposes all JVM and OS-level settings through System.getProperties(), which returns a Properties object:
public class SystemProps {
public static void main(String[] args) {
// Read a single system property
String javaVersion = System.getProperty("java.version");
String os = System.getProperty("os.name");
String userHome = System.getProperty("user.home");
System.out.println("Java version : " + javaVersion);
System.out.println("OS : " + os);
System.out.println("Home dir : " + userHome);
// Set a custom system property at runtime
System.setProperty("app.mode", "debug");
System.out.println("Mode: " + System.getProperty("app.mode"));
}
}
Output:
Java version : 21.0.3
OS : Linux
Home dir : /home/user
Mode : debug
Common system properties you’ll encounter:
| Property | Meaning |
|---|---|
java.version | JDK version string |
java.home | JRE installation directory |
os.name | Operating system name |
user.home | Current user’s home directory |
user.dir | Current working directory |
file.separator | / on Unix, \ on Windows |
line.separator | Platform-specific line ending |
path.separator | : on Unix, ; on Windows |
Default Properties (Fallback Chain)
You can chain Properties objects so that a lookup falls back to a parent set of defaults:
import java.util.Properties;
public class DefaultProperties {
public static void main(String[] args) {
// Base defaults
Properties defaults = new Properties();
defaults.setProperty("timeout", "30");
defaults.setProperty("retries", "3");
defaults.setProperty("log.level", "INFO");
// App-specific overrides
Properties appProps = new Properties(defaults);
appProps.setProperty("log.level", "DEBUG"); // overrides default
System.out.println(appProps.getProperty("timeout")); // from defaults
System.out.println(appProps.getProperty("retries")); // from defaults
System.out.println(appProps.getProperty("log.level")); // overridden
}
}
Output:
30
3
DEBUG
This fallback chain is useful when you have environment-specific overrides on top of a shared base configuration.
Under the Hood
Properties extends Hashtable<Object, Object>, which is a legacy synchronized hash table (similar to HashMap but thread-safe). Here is what that means in practice:
- Thread safety — all
Propertiesmethods are synchronized, so multiple threads can read and write safely. However, this synchronization also makes it slower thanHashMapfor single-threaded use. - String convention — the class was designed before Java generics. The
Object, Objecttype parameters are historical baggage. The dedicatedgetProperty()/setProperty()methods enforceStringtypes, and you should always use those instead of the rawput()/get()fromHashtable. - Load encoding —
load(InputStream)reads bytes as ISO-8859-1 (Latin-1) by default. To handle UTF-8 characters correctly, useload(Reader)with anInputStreamReaderspecifyingStandardCharsets.UTF_8. Java 9+ changed the default encoding for property files to UTF-8 when using the module system. list()vsstore()—list(PrintStream)is a debugging utility that truncates long values. Usestore()when you actually need to persist properties.
Warning: Avoid calling the inherited
put()method with non-String keys or values. It will compile fine (sinceHashtable<Object, Object>accepts anything), but it will breakgetProperty(), which only looks upStringkeys. Stick tosetProperty()/getProperty()exclusively.
Key Methods at a Glance
| Method | Description |
|---|---|
setProperty(key, value) | Store a string key-value pair |
getProperty(key) | Retrieve value or null |
getProperty(key, default) | Retrieve value with fallback |
load(InputStream) | Load from a byte stream (ISO-8859-1) |
load(Reader) | Load from a character stream (UTF-8 friendly) |
store(OutputStream, comment) | Save to a byte stream |
storeToXML(OutputStream, comment) | Save in XML format |
loadFromXML(InputStream) | Load from XML format |
stringPropertyNames() | Set of all String keys |
list(PrintStream) | Print all entries (for debugging) |
Related Topics
- HashMap — the modern, non-synchronized alternative to the Hashtable backing Properties
- Collections Utility Class — utility methods that work across the collections framework
- File Handling — reading and writing files, which you use when loading
.propertiesfiles - Serialization — another way to persist object state beyond plain text config
- JDBC Steps — a real-world use of
Propertiesto supply database credentials - Hashtable — the parent class of Properties and its thread-safety trade-offs