简体   繁体   中英

Java: How to “mutate” a string, despite a string's immutability?

I am developing an API as a bit of a student hobby-project, and I'm using a url where different options can be added/subtracted to change the information received. I know strings are immutable, which has made things a bit challenging to work around neatly. I've come up with a few a messy ways, none that robust, to solve it, and I'm wondering if there is a standard approach. I plan to have radio buttons (not assigned to a button a group; want all permutations) that will allow me to "include", "add", and "exclude" options.

Thus, here is the string z?s=GOOG&t=7m&z=l&q=l&p=e50,m50&a=ss,sfs,vm,w14 used to interact with YahooFinance API. So, assume that I have some variable like this:

 String options="z?s=GOOG&t=7m&z=l&q=l&p=e50,m50&a=ss,sfs,vm,w14"

Now, consider the part that says p=e50,m50 . Suppose I have three radiobuttons 50 , 100 , 200 that I want to tick on/off to such that I'd have a string p=e50,m50,e100,m100,e200,m200 with all buttons on, and every possible other combination; ie with 100 off, it would look like: p=e50,m50,e200,m200 .

Any thoughts? I'd like to ultimately do the same with the other value ( ss,sfs , etc.) as well, however, let's just start with the moving averages.

Use a StringBuilder and the insert method.

Java documentation page

Strings are only immutable in the sense that there is no way to change the contents of a particular instance of a string once it's created in the JVM. That said, that doesn't mean you can't construct strings on the fly that suit your needs. You could use simple concatenation and do something like...

String options="z?s=GOOG&t=7m&z=l&q=l&p=" + eOption + ",m50&a=ss,sfs,vm,w14";

Technically, this creates three String instances, and a StringBuffer is used to append them all together. You could use the StringBuffer API yourself and call .append() in the places you want to add options.

Using mutable strings would just lead to messy code. What you need is a data structure where it's easy to update the parameters, then traverse that data structure to create a string from it. I'd store these parameters in a map and write a function that would create the string from the map by iterating through the map entries.

So you'd store your parameters in the map like:

Map<String,String> map = new LinkedHashMap<>();
map.put("s", "GOOG");
map.put("t", "7m");

and generate the parameter string with something like:

public String createParameterString(Map<String, String> map) {
    StringBuilder builder = new StringBuilder("");
    for (Map.Entry mapEntry : map.entrySet()) {
        if (builder.length() != 0) builder.append("&");
        builder.append(mapEntry.key());
        builder.append("=")
        builder.append(mapEntry.value());
    }
    return builder.toString();
}

Usually, you break the string into parts, and assemble a new string. The caller can then either maintain a reference to the old and new string, or simply discard the old one.

As a stupid example:

String hairySally = "hairy,sally";
String hairyFredSally = insertFred(hairySally);


String insertFred( String s) {
    String[] parts = s.split(",");
    return parts[0] + ",fred," + parts[1];
}

What you're looking for is formatted strings , for instance:

String querystringFormat="z?s=GOOG&t=7m&z=l&q=l&p=%s&a=ss,sfs,vm,w14"

Note that e50,m50 has been replaced with %s , the format string code that indicates this part of the string will be replaced with another string.

Then, you would do whatever you do to build up your parameters, and do:

String params = "e50,m50,e100,m100,e200,m200", 
Formatter formatter = new Formatter();
formatter.format(querystringFormat, params);
String query = formatter.toString();

There's a lot of other options and details for using format strings, but that's the basic idea. The good part is that the unchanging part of the structure of your string is clear, and you only replace the parts that need replacing.

It'll also teach you how to use C and C++'s printf , which is never a bad thing :)

Why do you want to mutate a string? And why do you approach this problem from the String perspective? This question is not about text. What this sequence of characters

?s=GOOG&t=7m&z=l&q=l&p=e50,m50&a=ss,sfs,vm,w14

represents it's just a map (also called a dictionary), ie a collection of key-value pairs, serialized according to the URI encoding scheme and appended to the URL of a HTTP request. You don't want to keep track of the serialized parts, especially because a URI accepts only a small subset of characters, so if you reason in terms of strings, you'll likely end up with non-working code.

You need two methods: one to serialize a Map to the URI format, and one to get back a Map from its serialized form. Note that the Yahoo protocol uses a comma to assign multiple values to the same key. You have to account for this, too, when serializing and deserializing.

I wrote a gist for you. It's not thoroughly tested, but you get the idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM