Of course! Let's dive deep into querystring in Java.
First, a crucial point: Unlike Node.js, which has a built-in querystring module, Java does not have a standard library class named QueryString. Instead, Java handles URL query strings using its core java.net package, primarily with the URI and URL classes.
Here’s a complete guide on how to parse, build, and manipulate query strings in Java.
Parsing a Query String (The Most Common Task)
The best way to parse a query string is to use the java.net.URI class. It's robust, handles encoding/decoding correctly, and is part of the standard Java SE.
Using java.net.URI (Recommended)
This is the standard and safest approach.
Example URL:
https://www.example.com/search?q=java+programming&page=2&sort=desc
Goal: Extract the parameters (q, page, sort).
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
public class QueryStringParser {
public static void main(String[] args) {
String urlString = "https://www.example.com/search?q=java+programming&page=2&sort=desc&user=tom%40gmail.com";
try {
// 1. Create a URI object
URI uri = new URI(urlString);
// 2. Get the query string (the part after the '?')
String query = uri.getQuery();
System.out.println("Raw Query String: " + query); // q=java+programming&page=2&sort=desc&user=tom%40gmail.com
// 3. Parse the query string into a Map<String, String>
// We use a simple split for demonstration. For production, consider a library.
Map<String, String> params = parseQueryString(query);
// 4. Access the parameters
String searchQuery = params.get("q");
int pageNumber = Integer.parseInt(params.get("page"));
String sortMethod = params.get("sort");
String userEmail = params.get("user");
System.out.println("\nParsed Parameters:");
System.out.println("Search Query: " + searchQuery); // java programming (plus signs are decoded to spaces)
System.out.println("Page Number: " + pageNumber); // 2
System.out.println("Sort Method: " + sortMethod); // desc
System.out.println("User Email: " + userEmail); // tom@gmail.com (percent-encoding is decoded)
} catch (URISyntaxException e) {
System.err.println("Invalid URL: " + e.getMessage());
}
}
/**
* A simple method to parse a query string into a Map.
* Note: This is a basic implementation. It doesn't handle multiple values for the same key.
* For a more robust solution, see the "Using a Library" section below.
*/
public static Map<String, String> parseQueryString(String query) {
if (query == null || query.isEmpty()) {
return Map.of(); // Return an empty immutable map
}
// Split by '&' to get key-value pairs
return Arrays.stream(query.split("&"))
.map(pair -> pair.split("=", 2)) // Split by '=' into max 2 parts
.collect(Collectors.toMap(
arr -> URLDecoder.decode(arr[0], StandardCharsets.UTF_8), // Decode key
arr -> arr.length > 1 ? URLDecoder.decode(arr[1], StandardCharsets.UTF_8) : "" // Decode value
));
}
}
Key Points:
URI.getQuery(): This method correctly extracts only the query part (e.g.,q=java...).URLDecoder.decode(): This is essential. It correctly handles URL-encoded characters like%40(which becomes ) and (which becomes a space). Failing to decode this will lead to bugs.- Simple vs. Complex Values: The simple
split()method works well for most cases where each key has a single value.
Building a Query String
Building a query string manually is error-prone. You must remember to encode special characters (&, , , space, etc.). The best practice is to build a Map of parameters and then format it.
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class QueryStringBuilder {
public static void main(String[] args) {
// 1. Create a map of your parameters
Map<String, String> params = new HashMap<>();
params.put("q", "java & spring");
params.put("page", "1");
params.put("sort", "date");
params.put("lang", "en-US"); // Special characters like '-' are fine, but spaces are not
// 2. Build the query string
String queryString = buildQueryString(params);
// The result will be: q=java+%26+spring&page=1&sort=date&lang=en-US
System.out.println("Constructed Query String: " + queryString);
}
public static String buildQueryString(Map<String, String> params) {
if (params == null || params.isEmpty()) {
return "";
}
StringBuilder queryStringBuilder = new StringBuilder();
params.forEach((key, value) -> {
try {
// Encode both key and value to handle special characters
String encodedKey = URLEncoder.encode(key, StandardCharsets.UTF_8.name());
String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
if (queryStringBuilder.length() > 0) {
queryStringBuilder.append("&");
}
queryStringBuilder.append(encodedKey).append("=").append(encodedValue);
} catch (UnsupportedEncodingException e) {
// StandardCharsets.UTF_8 is guaranteed to be supported, so this is safe.
throw new RuntimeException("Failed to encode parameter", e);
}
});
return queryStringBuilder.toString();
}
}
Key Points:
URLEncoder.encode(): This is the counterpart toURLDecoder. It converts spaces to and special characters like&and into their percent-encoded form (%26,%3D).StandardCharsets.UTF_8: Always specify the character encoding. UTF-8 is the standard for the web.
Handling Multiple Values for the Same Key
A query string can have the same key multiple times (e.g., colors=red&colors=blue). The Map approach from above will not work, as a map cannot hold duplicate keys.
In this case, you should parse the query string into a Map<String, List<String>>.
Parsing Multiple Values
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
public class MultiValueQueryParser {
public static void main(String[] args) throws URISyntaxException {
String urlString = "https://example.com/filter?colors=red&colors=blue&size=large&colors=green";
URI uri = new URI(urlString);
String query = uri.getQuery();
// Parse into a Map<String, List<String>>
Map<String, List<String>> params = parseMultiValueQueryString(query);
System.out.println("Parsed Multi-Value Parameters:");
params.forEach((key, values) -> {
System.out.println(key + " -> " + values);
});
// Accessing a specific list of values
List<String> colors = params.get("colors");
if (colors != null) {
System.out.println("\nFirst color: " + colors.get(0)); // red
}
}
public static Map<String, List<String>> parseMultiValueQueryString(String query) {
if (query == null || query.isEmpty()) {
return Collections.emptyMap();
}
return Arrays.stream(query.split("&"))
.map(pair -> pair.split("=", 2))
.collect(Collectors.groupingBy(
arr -> URLDecoder.decode(arr[0], StandardCharsets.UTF_8),
Collectors.mapping(
arr -> arr.length > 1 ? URLDecoder.decode(arr[1], StandardCharsets.UTF_8) : "",
Collectors.toList()
)
));
}
}
Using a Third-Party Library (Recommended for Production)
While the standard library is good, a dedicated library can simplify your code significantly, handle edge cases, and provide a more fluent API. The most popular choice is Apache HttpClient.
Add the Dependency (Maven)
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version> <!-- Use the latest version -->
</dependency>
Parsing with URIBuilder
URIBuilder is an incredibly useful class that handles both parsing and building.
import org.apache.hc.client5.http.utils.URIBuilder;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
public class UriBuilderExample {
public static void main(String[] args) throws URISyntaxException {
// --- PARSING ---
String urlString = "https://www.example.com/search?q=java+programming&page=2&colors=red&colors=blue";
// The URIBuilder can parse a string directly
URIBuilder uriBuilder = new URIBuilder(urlString);
System.out.println("Host: " + uriBuilder.getHost());
System.out.println("Path: " + uriBuilder.getPath());
// Get a single parameter
String searchQuery = uriBuilder.getQueryParams("q").get(0).getValue();
System.out.println("Search Query: " + searchQuery); // java programming
// Get all values for a multi-valued parameter
List<String> colors = uriBuilder.getQueryParams("colors").stream()
.map(param -> param.getValue())
.toList();
System.out.println("Colors: " + colors); // [red, blue]
// --- BUILDING ---
System.out.println("\n--- Building a new URL ---");
URIBuilder newBuilder = new URIBuilder("https://api.example.com/data");
newBuilder.addParameter("id", "123");
newBuilder.addParameter("format", "json");
newBuilder.addParameter("tags", "java,http");
// Note: URIBuilder automatically adds '&' for you
URI newUri = newBuilder.build();
System.out.println("Constructed URL: " + newUri.toString());
// Output: https://api.example.com/data?id=123&format=json&tags=java%2Chttp
}
}
Why use a library like URIBuilder?
- Robustness: Handles complex URL edge cases correctly.
- Fluent API: The
addParameter()method is very readable. - Automatic Encoding: You provide raw values, and the builder handles the encoding.
- Multi-value Support: It's built-in and easy to use.
- Easy Modification: It's trivial to add, remove, or change parameters on an existing URI.
Summary: Which Method to Use?
| Scenario | Recommended Approach |
|---|---|
| Simple Parsing (single value per key) | URI.getQuery() + manual split() and URLDecoder.decode(). |
| Simple Building (single value per key) | Manual StringBuilder + URLEncoder.encode(). |
| Multi-value Parameters | URI.getQuery() + parse into Map<String, List<String>> with URLDecoder. |
| Production / Complex Applications | Apache URIBuilder. It's the most robust, readable, and maintainable solution. |
