Environment and Configuration

Accessing environment variables

Java provides access to environment variables via the System.getenv method. This method retrieves the value of an environment variable at runtime.

final String name = "EXAMPLE_ENVIRONMENT_VARIABLE"; String value = System.getenv(name); if (value == null || value.isEmpty()) { System.out.println("Environment variable '" + name + "' not set."); } else { System.out.println("Environment variable '" + name + "' set to '" + value + "'."); }

Rust provides the same functionality of accessing an environment variable at runtime via the var and var_os functions from the std::env module.

var function returns a Result<String, VarError>, either returning the variable if set or returning an error if the variable is not set or it is not valid Unicode.

var_os has a different signature giving back an Option<OsString>, either returning some value if the variable is set, or returning None if the variable is not set. An OsString is not required to be valid Unicode.

use std::env; fn main() { let key = "ExampleEnvironmentVariable"; match env::var(key) { Ok(val) => println!("{key}: {val:?}"), Err(e) => println!("couldn't interpret {key}: {e}"), } }
use std::env; fn main() { let key = "ExampleEnvironmentVariable"; match env::var_os(key) { Some(val) => println!("{key}: {val:?}"), None => println!("{key} not defined in the enviroment"), } }

Rust also provides the functionality for accessing an environment variable at compile time. The env! macro from std::env expands the value of the variable at compile time, returning a &'static str. If the variable is not set, an error is emitted.

use std::env; fn main() { let example_env_variable = env!("ExampleEnvironmentVariable"); println!("{example_env_variable}"); }

In Java, compile time access to environment variables can be achieved, but in a less straightforward way, using Reflection API. Generally this is not recommended in modern Java.

Configuration

Java does not have built-in support for configuration management. In order to work with configuration, we need to use third-party libraries, such as the Apache Commons Configuration library.

Here's the Maven dependency for the Apache Commons Configuration library that we can add to our pom.xml file:

<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-configuration2</artifactId> <version>2.11.0</version> </dependency>

And here's how we can make use of the library:

import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.builder.fluent.Configurations; import org.apache.commons.configuration2.ex.ConfigurationException; public class ExampleClass { public static void main(String[] args) { Configurations configs = new Configurations(); try { // Load environment variables Configuration configuration = configs.systemEnvironment(); // Retrieve the value of the environment variable "ExampleEnvVariable" String exampleEnvVariable = configuration.getString("ExampleEnvVariable"); System.out.println(exampleEnvVariable); } catch (ConfigurationException e) { e.printStackTrace(); } } }

A similar configuration experience in Rust is available via use of third-party crates such as figment or config.

See the following example making use of the config crate:

use config::{Config, Environment}; fn main() { let builder = Config::builder().add_source(Environment::default()); match builder.build() { Ok(config) => { match config.get_string("example_env_variable") { Ok(v) => println!("{v}"), Err(e) => println!("{e}") } }, Err(_) => { // something went wrong } } }