public String toEncodedString() {
        StringBuilder sb = new StringBuilder();
        try {
            for (Map.Entry<String, String> entry : entries()) {
                sb.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
                if (!Strings.isNullOrEmpty(entry.getValue())) {
                    sb.append('=');
                    sb.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                } else if (isTrailingEquals(entry.getKey())) {
                    sb.append('=');
                }
                sb.append('&');
            }

            // Remove trailing '&'.
            if (sb.length() > 0 && '&' == sb.charAt(sb.length() - 1)) {
                sb.deleteCharAt(sb.length() - 1);
            }
        } catch (UnsupportedEncodingException e) {
            // Won't happen.
            e.printStackTrace();
        }
        return sb.toString();
    }
@Test
    void testToEncodedString() {
        HttpQueryParams qp = new HttpQueryParams();
        qp.add("k'1", "v1&");
        assertEquals("k%271=v1%26", qp.toEncodedString());

        qp = new HttpQueryParams();
        qp.add("k+", "\n");
        assertEquals("k%2B=%0A", qp.toEncodedString());
    }