Writing non-repetitive code

I wish I could turn a string into a variable name.

For the implementation of Uri, I find myself writing very similar code for each of the components of the URI (scheme, userinfo, path, etc.)

I basically have blocks of code that are almost identical but instead of schemeRegex I have userRegex. I wish I could just pass in the word “query” to some function and the whole block would be written for me. Could this be solved by some component of URI class that has different attributes?

I considered doing something like organizing all the parallel commonalities into arrays but then you might lose some readability.

This is a recurring theme in my programming projects and I’d like to find a more general solution if it exists.

I once heard about something called “Macros” in passing. Is that relevant to what I’m looking for? Sorry for the rambling question. Thanks in advance.

There are tons of ways to deal with repetitive code (you can google “java patterns” or “java generics” to get a taste of what that might be) but from your question it sounds a lot like your are trying to parse something within a class implementing the interface Uri.

While that is technically possible it is not the intent of the project. Your implementation of the interface UriParser should handle all the parsing and then call a constructor for Uri and pass all the parsed information to it. Think of Uri more as a container that gathers a bunch of information in one place.

The parser itself can be done in a few lines but if you are struggling with Java I would not recommend attempting that (even though it seems like this is kinda what you want, sorry :grinning:).

If you want to turn strings into variable names, you should look at this:
https://docs.oracle.com/javase/8/docs/api/java/util/Map.html
Map is a bit like a dictionary in Python in that it allows you to access members by so called keys instead of indices like with arrays. The <K,V> behind the name means that you are free in choosing what type your keys and your values are. (this is an instance of “generics” as mentioned above)

Note that Map is an interface and can not be instantiated, in order to work with this you need to use a class implementing it. (I would suggest HashMap) You can then do stuff like this:

Map<String, Integer> map = new HashMap<>(); // creates a new map
map.put("age", 50); // add the key-value pair:          "age" : 50
map.put("height", 300); // add the key-value pair     "height" : 300
if (map.get("age") == 50) {
    doSomething();
}

Which creates a HashMap, puts two key-value pairs in it and then accesses a value (the age) by giving its key to the get method. (the statement doSomething() is executed)

Even cooler, you can iterate without that annoying integer counter:

for (String key : map.keySet()) {
    System.out.println(key.length()); 
}

will output:

3
6
1 Like

In general, you can use functions to extract common code. Sometimes you need to generalize a bit to factor common things out.
The repetition then becomes a simple function call.
Depending on what exactly you try to achieve a map as mentioned by Bastian might be helpful (although one probably does not need one here).
For a linear flow of similar code a simple for loop over the changing parts is the easy imperative way to avoid code duplication.

Side note:
There is a concept called metaprogramming where you write programs to write programs that allows for much higher flexibility and freedom than the concepts mentioned above. (generate multiple functions, rewrite functions, turn variables into strings and back, …)
The price is a bit more technical difficulty and theoretical knowledge that is needed.
Macros, like those used in the C preprocessor, are some simple form of metaprogramming.
However, metaprogramming is quite advanced and not needed in our programs. Do not use it here.

1 Like