Working with Environment Variables in Java
Tags: java
Published: 2024-03-22 13:09:44

## What is an Environment Variable?

Environment variables (sometimes called "env vars") are variables you store outside your program that can affect how it runs. You can later use that value to change how programs, applications, and services behave. Applications treat environmental variables like constants (a value that does not change during the program's execution) rather than mutable variables (a value that can change). They are best used with things you would typically consider hard coding but would rather keep the value out of your code, either because it will change between environments. You want to keep your code portable and easier to manage because you want to avoid leaking sensitive information such as your API key and password in less secure environments like development or testing.

## Use Cases

Here are a few use cases for environmental variables:

* Defining program arguments
* Specifying domain names
* Storing API keys
* Setting path variables

Let’s dive into each!

### Defining Program Arguments

* **How It Works**: Developers use environment variables like `ENV_MODE` to indicate the current execution context of the application, such as development, testing, staging, or production.
* **Benefits**: This allows the application to adapt its behavior based on the mode. For instance, in development mode, the application might enable verbose logging and debugging tools, whereas in production, these features are disabled for efficiency and security.
* **Implementation Example**: In Java, you might check `System.getenv("ENV_MODE")` to configure database connections or error handling differently for each mode.

### Specifying Domain Names

* **How It Works**: Environment variables like `SERVICE_URL` can store domain names or URLs that the application might need to access.
* **Benefits**: This is particularly useful for applications that interact with different endpoints or services in different environments. By changing the environment variable, you can redirect your application to use a different domain without altering the code.
* **Implementation Example**: In a Java-based web application integrating Vonage services, the endpoint URL for Vonage's API can be defined using an environment variable, like `VONAGE_API_URL`. This allows developers to switch between a local development environment and a production server by simply changing the value of the environment variable. The application retrieves this URL with `System.getenv("VONAGE_API_URL")`.

### Storing API Keys

* **How It Works**: Sensitive information such as API keys can be stored in environment variables, for instance, `API_KEY`.
* **Benefits**: This practice keeps sensitive data out of the source code, enhancing security. It also makes it easy to update keys without needing to touch the codebase, and different keys can be used in different environments.
* **Implementation Example**: In a Java application using Vonage services, the Vonage API key can be stored in an environment variable, such as `VONAGE_API_KEY`. To access this key, the application would use `System.getenv("VONAGE_API_KEY")`. This approach ensures the API key is not embedded in the source code or exposed in version control, enhancing security while providing access to Vonage's telecommunication services.

### Setting Path Variables

* **How It Works**: Environment variables like LOG_PATH or CONFIG_DIR can be used to specify the application's directory paths for logging, configuration files, or other purposes.
* **Benefits**: This allows for flexible file management, as paths can be changed per environment without code changes. It’s beneficial for applications on multiple platforms (like Windows and Unix), where directory structures can vary significantly.
* **Implementation Example**: In a Java application, reading a configuration path from an environment variable allows it to quickly adapt to different file system layouts across development and production servers or operating systems.


In all these cases, environment variables provide a layer of abstraction that separates configuration details from the application logic. This separation not only enhances security and maintainability but also increases the adaptability of the software to different environments and conditions.

## Getting Environmental Variables

Accessing environment variables in Java is straightforward and can be done using the System class provided by the standard Java library. Here's a simple guide on how to do it:

1. **Get a Single Environment Variable**: Use the System.getenv(String name) method to retrieve the value of a specific environment variable. For example, to access an environment variable named `API_KEY`, you would use:

```java
String apiKey = System.getenv("API_KEY");
```

2. **Check for Null Values**: It's a good practice to check if the environment variable is null (i.e., not set) to avoid potential NullPointerExceptions. For example:

```java
String apiKey = Optional.ofNullable(System.getenv("API_KEY")).orElse(otherValue);
```

where `otherValue` is the fallback. You can throw an exception instead if the environemnt variable is missing like so:

```java
Optional.ofNullable(System.getenv("API_KEY")).orElseThrow(() -> new IllegalStateException("API_KEY env var is not defined"));
```

3. **Get All Environment Variables**: To get a `Map<String, String>` of all environment variables, use `System.getenv()`. This is useful if you want to iterate over all available environment variables. For example:

```java
Map<String, String> envVars = System.getenv();
for (String envName : envVars.keySet()) {
    System.out.format("%s=%s%n", envName, envVars.get(envName));`
}
```

Alternatively, this can be written in one line:
```java
System.getenv().forEach((k, v) -> System.out.println(k+"="+v));
```

## Setting Environmental Variables

Setting environment variables directly within a Java application is not straightforward because environment variables are typically set at the operating system level and are read-only without an argument. However, there are a few ways you can work around this limitation, depending on your use case:

### Set Environment Variables Before Running Java Application

The most common approach is to set environment variables in your operating system before starting your Java application. This can be done in the command line or through scripts.

For example, in a Unix environment, you can set an environment variable in the terminal like this:

```sh
export MY_VAR="some value"
```

In Windows Command Prompt, it would be:

`set MY_VAR=some value`

### Set for Sub-Processes

If you need to set environment variables for [subprocesses](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ProcessBuilder.html) started from your Java application (and not for the Java process itself), you can use the ProcessBuilder class:

```java
ProcessBuilder processBuilder = new ProcessBuilder();
Map<String, String> env = processBuilder.environment();
env.put("MY_VAR", "some value");
Process process = processBuilder.start();
```

### Set Environment Variables in IDE

If you are using an Integrated Development Environment (IDE) like [IntelliJ IDEA](https://www.jetbrains.com/idea/) or [Eclipse](https://www.eclipse.org/ide/), you can set environment variables in the configuration settings of your application.

### Set Environment Variables in Build Tools

When using build tools like [Maven](https://maven.apache.org/) or [Gradle](https://gradle.org/), you can configure environment variables in the build scripts or configuration files.

## Loading Configurations From a File

Since `java.util.Properties` implements the Map interface, you can load any file which maps key-value pairs like so, irrespective of its file extension:

```java
var props = new Properties();
var envFile = Paths.get("/path/to/MyEnvConfig.env");
try (var inputStream = Files.newInputStream(envFile)) {
	props.load(inputStream);
}
String apiKey = props.get("VONAGE_API_KEY");
String apiSecret = props.get("VONAGE_API_SECRET");
```

## Share Your Best Practices

Getting and setting environment variables is an essential part of creating production software. If you’ve reached the end of this article, you’re now familiar with what environment variables are, use cases, how to get and set environment variables, and using .env files in Java. Feel free to join our community [Slack](https://developer.vonage.com/en/community/slack) and follow us on [X](twitter.com/VonageDev), formerly known as Twitter. Do you have other best practices using environmental variables? Please share them and [tag me](twitter.com/dianasoyster) - I'd love to hear about them!