A new Code Review process has been put in place and now my team must not ever declare a string as a local variable, or the commit won't pass the code review. We are now to use constants instead.
So this is absolutely not allowed, even if we're dead sure the string will never be used in any other place
String operationId = "create";
This is what should be used instead:
private static final String OPERATION_ID = "create";
While I totally agree to use constants for strings that appears +2 times in the code ... I just find it overkill to completely not have the ability to declare a string in place if it's used only once.
Just to make sure it's clear, all the following are NOT ALLOWED under any circumstances:
String div = "div1";
Catch(Exception ex){ LOGGER.log("csv file is corrupt") }
String concatenation String str = "something ...." + someVar + "something" ... we are to replace someVar with %s, declare whole thing as a global string, and then later use String.format(....)
if( name.equals("Audi" ){....}
String value = map.get("key")
Any ideas guys ? I want some strong arguments. I'm ready to embrace any stand that's backed by a good argument.
Thanks.
First, let's throw out your assumption: There's nothing inherently wrong with the approach described.
It's not about strings being used in more than one place, it's about constants being easy to find and documented, and your code being consistent.
private static final String OPERATION_ID = "create";
Really, this isn't used anywhere else? Nothing would break if I changed this to the string "beetlejuice"? If something would break, then something else is using this constant... If the "something else" happens to be a codebase in a different language, and that's why they don't share string constants-- that's the exception, not the rule. Consistency!
That said, there are a few things I would standardize in a slightly different manner, but I would still standardize them nonetheless:
I would suggest allowing string literals in the constructors of enums:
public enum Operation {
CREATE("create"),
...
}
because here, the enum is the constant that is being referenced in the code, not the string literal. Declaring the constant as an enum or as a private static final String are equivalent to me, and there's no need to do both.
Additionally, I would not use this pattern anywhere that it breaks your IDE's ability to warn you about missing strings-- For example, looking up strings from .properties files. Many IDEs will give you proper warnings when you look up a key in a .properties file that doesn't exist, but the extra level of indirection might break that depending upon how smart your IDE is.
Catch(Exception ex){ LOGGER.log("csv file is corrupt") }
This to me is a bit of a gray area - Is this an internal-only message? Are the logs only ever seen by you, the developer, or are they for a user's benefit too?
If it's only for developers of the application These probably don't need to be localized.
If you do expect the user to view the logs, then they should be externalized into a .properties file.
It is good coding style to define a constant for a value/literal when the value/literal is used multiple times.
The imposed coding style forces you to use a constant for every string literal.
The good effect of that coding style is: All string literals which really should be declared as constants are now declared as constants.
The bad implication of that coding style is: You - the developers - are not able to decide if a string literal should be defined as constant or not. This is a heavy punch.
Therefore you should raise your concerns that the good intention of the coding style does not compensate for the mistrust in your developer qualitites.
Related
I need your support and thanks for your Java/Annotations support..
I would to create a custom annotation f.e. #ModifyRegex to annotatate variables
and my approach is to modify/replace parts of the value of the annotated variables.
f.e.
#ModifyRegex
private String variable;
if:
variable = "AbC-ABG-kkkk-4711";
then:
variable = "ABC-4711-ABG-kkkk";
I am not sure if its possible or not, if yes please provide me a simple code example..
Thanks
Annotation processors can make new source files. They cannot change existing ones. They also cannot read inside methods. They can't read any code, in fact, so the only string literal that you could possibly see is if it's literally (heh) a literal. The java lang spec defines when the value assigned to a field is considered 'compile time constant' and is written straight in. If it's not, say:
class Example {
// these are all NOT constant, therefore, cannot be
// retrieved with an annotation processor
long x = System.currentTimeMillis();
Pattern p = Pattern.compile("^AbC-ABG-$");
String s = null; // null is considered non-constant, for some reason.
String z = "HELLO!".toLowerCase();
}
But, if it's truly simple, such as #Foo private String x = "Hello"; where x is a field (and not a local variable in a method someplace), yes, you can see it in action.
But all you can do, is make new files. You can't change an existing file. So, at best, you can make a second class that contains public static final String variable2 = "ABC-4711-...";.
But what about lombok?
Project Lombok does everything I just said you can't do: It inspects actual code, and modifies source files in-flight.
Unfortunately, lombok is a few hundred thousand lines of code and most of it is neccessary to do all this: There is no uniform way to do it, so it's a ton of custom code. More to the point, it is also fundamentally extremely complicated: IDEs do code analysis all the time, and if you change structures, that has an effect on everything from 'auto-format my file as it is saved' to refactor scripts, to 'find callers', and so much more. Because there is no standard, you have to patch the editors to figure it out.
Changing a string constant may mean you don't need as much patching. Then it's still incredibly complicated.
Lombok is open source if you want to investigate.
NB: I'm a core contributor to Project Lombok.
What is the overall advantage (in terms of memory management, etc.) of creating a separate constants file, like below class "Constants", over directly writing in Java file like stringVar.equals("name")?
public final class Constants {
// Hide the constructor
private Constants(){}
public static String NAME="name";
}
I know that even if we write use "name" 2 times (as below), only one literal will be created in String pool?
stringVar1.equals("name") and stringVar2.equals("name")
One reason would be to reuse it (and as a consequence prevent bugs from typos).
If you are using an IDE, it also becomes easier to perform a usage-lookup in a bit more non-ambiguous manner than plain string search.
The other as already noted in the comment, would be memory but as I see it, the above two reasons are far more significant - in general usage. My bad. Looks like memory has not much to do with it - atleast in case of static-final fields .
It's not about efficiency; it's about maintainability.
The constant both defines the value "name" in a single place, and associates a constant name (you chose NAME) with it.
In your example, the constant name doesn't tell us anything. But it could be, for example, public static String FIRST_NAME_FIELD = "name". Then it would be more clear, both in the Constants class and at every usage, what the string "name" means.
And, of course, if you need to change "name" to "first_name" later, it's easier.
Performance wise, java tend to reuse Strings in the String pool.
Constants are usually used when you know the value won't change or must not be changed by anyone else.
For a constant you must add final to you variable declaration:
public static final String NAME="name";
Constants are more related to better coding, organization and reuse than to performance.
Is it a good idea to declare all text getting used for logging as public static final from performance point of view or otherwise ?
Does it have any advantage other than readability in case one string is getting used only once ?
First, the objective part of your question: is there a performance benefit from declaring a log statement static final, i.e:
private static final String SUCCESS = "Success!";
//[...]
log.info(SUCCESS);
log.info(SUCCESS);
// versus:
log.info("Success!");
log.info("Success!");
The JLS states in section 3.10.5:
[A] string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (ยง15.28) - are "interned" so as to share unique instances, using the method String.intern.
So whether your string literal is declared once as a static final or appears multiple times in the source code, it will always be the same String instance, wherever it is used, and thus take up the same amount of memory, and will be accessed in exactly the same way. There will be no performance difference.
Now the other part of the question: is it a good idea? That is inherently subjective, but my opinion is that you should avoid declaring log messages as static final. Log messages add to the readability of the code, which is especially valuable when the code is being maintained by people who did not write it. For example:
log.warn(LOGIN_ERROR_OCCURRED, userId, attempt);
// compared to:
log.warn("Login failed for user {}; attempt {} of 5.", userId, attempt);
It's much quicker and easier to read the log message in the context of the code, rather than having to jump somewhere else in the code to see the full log message.
Easier internationalization and localization are possible advantages of using identifiers for string constants.
ResourceBundle bundle = ...
private final static LOGIN_ERROR_OCCURRED = bundle.getString("Login failed for user {}; attempt {} of 5");
But the benefits of i18n/L10n for log messages may be questionable.
Logging strings almost certainly should not be declared public, at least not usually. In most cases, it's better to declare constant variables for them, but sometimes you can be loose about that. Constants should appear together near the top of the class source, so for logging strings this gives a good overview of what happens in the class. It also makes it easier to find them for maintenance, like to edit out silly extraneous exclamation points. (Don't laugh; I've seen them.) I disagree that they obscure the point of log messages, unless you suck at naming variables. Which far too many people do.
My perception for defining string constants in Java is that one should define a string constant, when the same string is used at multiple places. This help in reducing typo errors, reduce the effort for future changes to the string etc.
But how about string that are used at a single place. Should we declare string constant even in that case.
For eg. Logging Some counter (random example).
CounterLogger.addCounter("Method.Requested" , 1)
Is there an advantage of declaring constant rather than using raw string?
Does the compiler does any optimization?
Declaring constants can improve your code because they can be more descriptive. In your example
CounterLogger.addCounter("Method.Requested" , 1)
The method parameter "Method.Requested" is quite self describing but the 1 is not making this a constant would make this example more readable.
CounterLogger.addCounter("Method.Requested" , INITIAL_VALUE)
The way I see it, Strings can be used in one of two ways:
As properties / keys / enumerations - or in other words, as an internal representation of another Objects/states of your application, where one code component writes them, and another one reads them.
In UI - for GUI / console / logging display purposes.
I Think it's easy to see how in both cases it's important to avoid hard-coding.
The first kind of strings must (if possible) be stored as constants and exposed to whichever program component that might use them for input/output.
Displayed Strings (like in your Logger case) are strings that you might change somewhere in the future. Having them all stored as static final fields in a constants-dedicated class can make later modifications much easier, and help avoid duplicates of similar massages.
Regarding the optimization question - as others have already answered, I believe there's no significant difference.
Presumably, you'll want to write a unit test for whichever method contains that line of code. That unit test will need access to that String value. If you don't use a constant, you'll have the String repeated twice, and if you have to change it in the future, you'll have to change it in both places.
So best to use a constant, even though the compiler is not going to do any helpful optimisations.
In my view in your case is fine. If you cant see any advantage in declaring it as a constant dont do it. To support this point take a look at Spring JdbcTemplate (I have no doubt that Spring code is a good example to follow) it is full of String literals like these
Assert.notNull(psc, "PreparedStatementCreator must not be null");
Assert.notNull(action, "Callback object must not be null");
throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
but only two constants
private static final String RETURN_RESULT_SET_PREFIX = "#result-set-";
private static final String RETURN_UPDATE_COUNT_PREFIX = "#update-count-";
Iterestingly, this line
Assert.notNull(sql, "SQL must not be null");
repeats 5 times in the code nevertheless the authors refused to make it a constant
It seems many places incorporate as best practice the use of class constants for SQL strings.
So instead of:
String sql = "select * from users";
PreparedStatement stmt = conn.prepareStatement(sql);
It's preferred to do:
private static final String SQL_SELECT_USERS = "select * from users";
void someMethod() {
...
PreparedStatement stmt = conn.prepareStatement(SQL_SELECT_USERS);
...
}
What are the advantages to the latter? It seems to me it's less readable.
Thanks.
If it is a short text and it is used only in one place then there is no need to make it a field. In your case it could be this
PreparedStatement stmt = conn.prepareStatement("select * from users");
You can find a lot of this kind of coding style in JDK source, like this one
if (is == null) {
throw new IllegalArgumentException("InputStream cannot be null");
}
A final variable cannot be changed, by mistake or otherwise. Declaring the statement string as final makes sure to avoid this bug:
String s = "select * from users";
// many lines of code
s = "temp";
// do something with s
// many lines of code
PreparedStatement stmt = conn.prepareStatement(sql);
No matter how many lines of code you add after declaring s, if s is final the compiler will tell you when some code attempts to clobber it with a new value.
If you always do the prepared statement immediately after the variable, then simple proximity will help you avoid this error. Also, your actual example used a better name (sql rather than just s). But still, you never know who will edit your code after you write it.
Any time you can use a feature of the language to get the compiler to help you, you should do it. In this case, the final declaration lets the compiler protect you from someone clobbering your pre-defined string. Admittedly in this specific example the benefit seems pretty small, but in general constant things should be declared final and I don't see any reason to break that rule for this case.
As for declaring it private, that is just typical data hiding. If this string isn't part of the "interface" to this class, it should be private; by default, make everything private, and only make the interface stuff public.
EDIT: One more point worth considering. If you have a literal string that contains SQL, and you make some mistake when writing the SQL, the compiler cannot help you. "selct * from users" is a perfectly valid string; the Java compiler doesn't know it's an SQL error, so you find out at runtime.
You can make constants that are SQL fragments, and put them together with string concatenation. The great part about this is that if you misspell something, now you likely have a compiler error.
private final String SELECT_STAR_FROM = "select * from ";
private final String USERS_TABLE = "users";
// many lines of code
PreparedStatement stmt0 = conn.prepareStatement(SELECT_STAR_FROM + USERS_TABLE);
// this line would fail at run time
PreparedStatement stmt1 = conn.prepareStatement("selct * from users");
// this line fails at compile time and the compiler points you at it
PreparedStatement stmt0 = conn.prepareStatement(SELCT_STAR_FROM + USERS_TABLE);
When you do JNI programming you need to specify function signatures with cryptic codes. I made a bunch of constants and my JNI programs concatenate the constants together to build up the function signatures. This is C code, not Java, but it illustrates the same idea as the above.
#define JSIG_CONSTRUCTOR "<init>"
If I made a typo and wrote "<intt>" for a constructor, the C compiler couldn't help me; it would be a runtime error (JNI would fail to find the constructor). But if I use JSIG_CONSTRUCTOR in my code, if I make a typo, the compiler will tell me.
There are really two issues at play here. The first is declaring the variable final; this provides a little bit of safety (you can't accidentally modify it later on, introducing a potentially intermittent runtime bug), and it indicates to anyone reading the code that the value is meant to be a constant.
Pulling the string out into a constant field (static final) is a bit more efficient and helps collect the important values in the class in one place. If the query statement is buried in someMethod(), it's harder to find and can't be reused between methods. By using class-level constants instead of "magic values", IDEs and Javadoc can identify their role, and developers needing to change the code later can find them more easily.
This is just one example of a very old (and very reasonable) programming practice of using constants instead of literals, e.g. the SQL_SELECT_USERS variable, instead of the "select * from users" literal string.
A similar approach is applicable (and advisable) for using numbers (e.g., BUFFER_SIZE instead of 4096) or any other type of value that is constant throughout the code of a class (or more than one classes). Constants (i.e., variables that are initialized only once and never change) in Java are declared using the final keyword.
Such is not a "less readable" strategy, either. On the contrary, if the name of the constant is intuitive, it makes much more sense than having the literal used in its place. Most importantly, after the constant is declared, it can be used as many times as necessary in the code and if, later on, its value needs to be changed (a very common case, indeed), the (whatever) change only needs to happen in one place (that of the declaration of the constant), instead of having to search through classes to make all the changes.
For constants that represent numbers, using the actual number instead of a single constant is called using a magic number in the code. That is not advisable because, after a while, it is difficult to remember why a value is defined as such. A constant with an intuitive name solves that problem.
So, using constants instead of literals is a strongly advisable programming habit to adopt.
The static final is no more "secure", nor is it faster, than simply coding the string literal at the point of use. (The number of strings would be the same, since literals are always interned, and the static final gets converted to a literal by the compiler anyway.)
The reason for using a more global value is to allow the string to be coded only once, vs being re-coded several places, and to collect all of the SQL string definitions in one location. This can be a good idea or a bad one, depending on circumstances (and the abilities of the programmer). One problem is that it can greatly obfuscate the code. Another is that if the value is defined in another class it must be class-prefixed, leading to some long names (If it's not defined globally like this then the advantage of coding only once is apt to be lost.)
It should be noted that it's foolishness to use this technique to "improve security", and then fail to use prepared statements for operations using externally-provided data values.