String concatenation - Boolean hard-coded Vs Boolean Concatenation with String - java

I need a advice (both in java & .net) for the following piece of code.
public void method(bool value)
{
String someString;
//some code
if (value)
{
//some code
...
someString = "one" + value;
}
else
{
//some code
...
someString = "two" + value;
}
}
Which one is advisable and why? either code like above or code like
someString = "onetrue";
someString = "twofalse";

After compilation and optimization by JDK, method will look like:
public static String method(boolean value) {
String someString;
if (value) {
StringBuilder sb = new StringBuilder();
sb.append("one");
sb.append(value);
someString = sb.toString();
} else {
StringBuilder sb = new StringBuilder();
sb.append("two");
sb.append(value);
someString = sb.toString();
}
return someString;
}
If this code is invoked very frequently, it could bring a performance impact, compared to the second version. In each case a new StringBuilder is constructed and three methods are invoked on it. And boolean should be converted to an object before calling append. While in the second version we just return constant. Everything depends on how often this code is called.

Neither will make any difference it's purely style.
Since you have // some other code I'd just stick with the first. If you only had one line in each branch then either is ok.

At a high level they both are the same but if you look down at lower levels, I would advise to using the method:
someString = "onetrue";
someString = "twofalse";
This is because when you do "one" + value, the value is actually a bool and the toString() method of the bool object will be called to add to the string. Basically just adding another step opposed to just specifying what to add to the string.

Related

What is better to use just one method with switch or 4 different methods?

I have a object and i get some fields from it, i made a method with a switch statement, the idea was make it generic and just call this method through parameters but now I´m not sure.
The options are
private String getCode(Row row, String code) {
String result;
switch (code) {
case code1:
result = row.getString("constant1");
break;
case code2:
result = row.getString(constant2);
break;
case code3:
result = row.getString(constant3);
break;
case code4:
result = row.getString(constant4);
break;
default:
result = null;
}
return result;
}
or
private String getcode1(Row row){
return row.getString("constant1")
}
private String getcode1(Row row){
return row.getString("constant2")
}
private String getcode1(Row row){
return row.getString("constant3")
}
private String getcode1(Row row){
return row.getString("constant4")
}
I wand to use the better way, I´m a little confuse
The answer is neither of the them.
What you have here is a value conversion process. How this works? Well, as far I understand, you need to store the data in form of key-value pair where key must be unique. So this is the definition of a HashMap in java.
Also, because you are using Switch I'm assuming that you can identify your data with some unique key. This meas for each code there is only one constant. But how we can apply this to my issue? Well, I think you have a collection of data from where you extracted a single row. Now, from this row you want to access to a value (lets call it codeValue) using a constant, but to get this constant you need a code. Like this: code->constant->codeValue
How can I implement this??
Well, we gonna need a HasMap() called constants, which defines its keys a codes and the values as constants. Now you easily get each constant if you know its code. Obviously, if you get the constant you can also get the codeValue of each `row, like this:
public class TestClass {
public static void main(String[] args) {
// Create a HashMap object called constants
Map<String, String> constants = new HashMap<String, String>();
// Add keys and values (code, constant)
constants.put("code1", "constant1");
constants.put("code2", "constant2");
constants.put("code3", "constant3");
constants.put("code4", "constant4");
System.out.println(constants);
Row row = loadRow();
String code = loadCode();
//How to use it
String result = getCodeValue(row, code);
System.out.println(result);
}
// Now you get the code from the Map
private String getCodeValue(Row row, String code) {
return row.getString(constants.get(code));
}
}
In case your input code is different than constant, I will suggest the following approach. Create an Enum mapping code and constant.
public enum Mapping {
MAPPING_FIRST("code1", "constant1"),
MAPPING_SECOND("code2", "constant2");
private String code;
private String constant;
// constructor and getters
public static Mapping getMappingFromCode(String code){
return Arrays.stream(Mapping.values())
.filter(mapping -> mapping.getCode().equals(code))
.findFirst()
.orElse(null);
}
}
Now, create a method to access value from row.
private String getValue(Row row, String code) {
Mapping mapping = Mapping.getMappingFromCode(code);
if(mapping == null){
return null;
}
return row.getString(mapping.getConstant());
}
This question is little bit to much, but I will try to explain best I could. For me second option is no no at all. Why? You are making methods that you will have to sort out with some if/else statements anyway, for example:
if (code.equals(code1))
someString = getcode1(row);
else if (code.equals(code2))
somestring = getcode2(row);
else if (code.equals(code3))
someString = getcode3(row);
else
someString = getcode4(row);
Why not use this:
if (code.equals(code1))
someString = row.getString("content1");
else if (code.equals(code2))
somestring = row.getString("content2");
else if (code.equals(code3))
someString = row.getString("content3");
else
someString = row.getString("content4");
The first one I can see being used, but there is alternative there. Give us entire minimal requirement code with entire class and methods and we could help you far more than using these snippets of code.
Create an enum for mapping of code and constant. In that enum, create a generic method where you can get code just passing through parameter.
public enum MyEnum {
CODE1("constant1"), CODE2("constant2");
private String constant;
public String getConstant() {
return constant;
}
private MyEnum(String constant) {
this.constant = constant;
}
private static String getConstant(String code) {
return Arrays.stream(MyEnum.values()).filter(mapping -> mapping.name().equalsIgnoreCase(code))
.map(e -> e.getConstant()).findAny().orElse(null);
}
public static String getCode(Row row, String code) {
String constant = getConstant(code);
return constant != null ? row.get(constant) : null;
}
}
You can get code from row object by calling genric method getCode().
MyEnum.getCode(row, "code1")

Should one use StringBuilder in a recursive function?

I understand that the purpose of StringBuilder (usually) is to avoid creating objects over and over in Java when iterating over strings, especially in a loop.
I'm wondering if it's worth it to use it in a recursive function that returns a string. In other words, which of the following is more efficient?
public String recursive(int n) {
String retStr = "s";
if (n==0) {
return retStr;
}
else {
return retStr + recursive(n-1);
}
}
or
public String recursive(int n) {
String retStr = "s";
StringBuilder sb = new StringBuilder();
if (n==0) {
return retStr;
}
else {
return sb.append(retStr).append(recursive(n-1)).toString();
}
}
If I had to guess, the first one seems less complex, because either way you have to create a new object, be it a String or a StringBuilder, every time, but I could be wrong.
You can add StringBuilder to recursive method:
public String recursive(int n, StringBuilder sb) {
String retStr = "s";
if (n==0) {
return retStr;
}
else {
return sb.append(retStr).append(recursive(n-1, sb)).toString();
}
}
and call it
recursive(100, new StringBuilder());
if you are using java 8,
Since variables are in scope I think there is no need for StringBuilder.
In summary, Java 8 seems not to introduce new optimizations for String
concatenation with the + operator. It means that using StringBuilder
manually is still required for specific cases where the compiler or
the JIT is not applying magic tricks. For instance, when lot of
substrings are concatenated to a String variable defined outside the
scope of a loop.
See more in pellegrino
and dzone
User7294900's idea to pass the StringBuilder is fine, but he is adding much too much.
public String recursive (int n, StringBuilder sb) {
String retStr = "s";
if (n==0) {
return sb.toString ();
}
else {
return recursive (n-1, sb.append (retStr));
}
}
And - you should look this up, I'm unsure - doesn't the StringBuilder take hints, how big it will grow?
recursive (100, new StringBuilder (101));

Deleting A Specified Substring in Java

This is actually an exercise from CodingBat. The definition of the problem is as follows:
Given a string, if the string "del" appears starting at index 1, return a string where that "del" has been deleted. Otherwise, return the string unchanged.
delDel("adelbc") → "abc"
delDel("adelHello") → "aHello"
delDel("adedbc") → "adedbc"
My work is as follows:
public String delDel(String str) {
String del = "del";
if (str.indexOf(del, 1) == 1){
str.replaceFirst("del", null);
}
return str;
}
It works fine for most of the cases, but I get NullPointerException in "adelbc", "adelHello" and "adel" cases. I can't quite understand why.
If you look closely in the OpenJDK sources, you'll note that replaceFirst delegates work to the regexp functions, including this one for replacing step:
public String replaceFirst(String replacement) {
if (replacement == null)
throw new NullPointerException("replacement");
reset();
if (!find())
return text.toString();
StringBuffer sb = new StringBuffer();
appendReplacement(sb, replacement);
appendTail(sb);
return sb.toString();
}
Note that replacement can not be null. I assume the behaviour is going to be similar in other implementations of the JRE. Please use "" - empty string - instead of null as the replacement.
Also as mentioned in the comments by cricket_007 you want to save the result of replaceFirst for returning, since the original string will not be affected (all Strings in Java are immutable). The final piece of code:
public String delDel(String str) {
String del = "del";
if (str.indexOf(del, 1) == 1){
return str.replaceFirst("del", "");
}
return str;
}

Should the toString() method be added?

This is the piece of code.
List<BDDObject> childlist = savingObject.getChildren("TherapyAreaReference");
if (childlist.size() > 1) {
for (int i = 0; i < childlist.size() - 1; i++) {
String newMedcondRefChild = ((String) childlist
.get(i)
.getValue( IDDConstants.IDD_THERAPY_AREA_REF_VALUE))
.toLowerCase()
.trim()
.concat(((String) childlist
.get(i)
.getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME))
.toLowerCase().trim());
}
}
IDDConstants has public static final strings defined in it. As StringBuffer is more effective, how can it be incorporated for the concat operations?
I'm guessing that the intention is to generate a list of 'reports', one for each BDDObject record found. Based on that idea, your code should look more like this:
public List<String> getReport(List<BDDObject> records) {
List<String> reports = new ArrayList<String>(record.size());
for (BDDObject record:records) {
String newMedcondRefChild = String.valueOf(record.getValue( IDDConstants.IDD_THERAPY_AREA_REF_VALUE))
.toLowerCase()
.trim() + String.valueOf(record.getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME)))
.toLowerCase().trim());
reports.add(newMedcondRefChild);
}
return reports;
}
Regarding the question on whether toString() would be helpful, the only place where I see it fitting, would be on the BDDObject itself. It would look something like this:
class BDDObject {
...
#Override
public String toString() {
return String.valueOf(getValue(IDDConstants.IDD_THERAPY_AREA_REF_VALUE)).toLowerCase().trim() +
String.valueOf(getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME)).toLowerCase().trim());
}
In which case, the function to create the report becomes trivial:
public List<String> getReport(List<BDDObject> records) {
List<String> reports = new ArrayList<String>(record.size());
for (BDDObject record:records) {
reports.add(record.toString());
}
return reports;
}
In case that what you want is a looooong string with all the values concatenated to it, you can use StringBuilder, like this:
public String getReport(List<BDDObject> records) {
StringBuilder sb = new StringBuilder();
for (BDDObject record:records) {
sb.append(String.valueOf(record.getValue( IDDConstants.IDD_THERAPY_AREA_REF_VALUE))
.toLowerCase()
.trim());
sb.append(String.valueOf(record.getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME))
.toLowerCase().trim()));
}
return sb.toString();
}
This will return all the records appended after each other. I doubt its readability, but you I hope you get the idea. StringBuilder is helpful when you need to build a string iteratively (like in the previous example). StringBuilder should not be used to replace single String operations like : String a = b.get() + c.get(); given that the compiler implicitly creates a StringBuilder in these cases and therefore there's no actual performance improvement to be achieved.
In the code in your question, StringBuffer/StringBuilder will not give you any performance gains, because you concatenate only two strings. However, the question does not state what you are doing with the string in newMedconfRefChild. If your actual goal is to concatenate the strings of each loop iteration, then you should use a StringBuilder (use StringBuffer only when it is really necessary, prefer StringBuilder).

Java: StringBuffer & Concatenation

I'm using StringBuffer in Java to concat strings together, like so:
StringBuffer str = new StringBuffer();
str.append("string value");
I would like to know if there's a method (although I didn't find anything from a quick glance at the documentation) or some other way to add "padding".
Let me explain; every time I append something to the string, I want to add a space in the end, like so:
String foo = "string value";
str.append(foo + " ");
and I have several calls to append.. and every time, I want to add a space. Is there a way to set the object so that it will add a space automatically after each append?
EDIT --
String input
StringBuffer query = new StringBuffer();
Scanner scanner = new Scanner(System.in);
scanner.UseDelimiter("\n");
do {
System.out.println("sql> ");
input = scanner.next();
if (!empty(input)) query.append(input);
if (query.toString().trim().endsWith(";")) {
//run query
}
}
while (!input.equalsIgnoreCase("exit");
I'll use StringBuilder though as grom suggested, but that's how the code looks right now
I think this is handled easier either with a helper method (untested code):
public String myMethod() {
StringBuilder sb = new StringBuilder();
addToBuffer(sb, "Hello").addToBuffer("there,");
addToBuffer(sb, "it").addToBuffer(sb, "works");
}
private StringBuilder addToBuffer(StringBuilder sb, String what) {
return sb.append(what).append(' '); // char is even faster here! ;)
}
Or even using a Builder pattern with a fluent interface (also untested code):
public String myMethod() {
SBBuilder builder = new SBBuilder()
.add("Hello").add("there")
.add("it", "works", "just", "fine!");
for (int i = 0; i < 10; i++) {
builder.add("adding").add(String.valueOf(i));
}
System.out.println(builder.build());
}
public static class SBBuilder {
private StringBuilder sb = new StringBuilder();
public SBBuilder add(String... parts) {
for (String p : parts) {
sb.append(p).append(' '); // char is even faster here! ;)
}
return this;
}
public String build() {
return sb.toString();
}
}
Here's an article on the subject.
Hope it helps! :)
You should be using StringBuilder.
Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
StringBuffer is final. You cannot derive from it.
The Best solution really is to add the padding for yourself. Write a method for it and use a PADDING-Constant so that you can easily change it, or better put it in a parameter.
Can you not create a new class which wraps around StringBuffer and add an appendWithTrailingSpace() method?
CustomStringBuffer str = new CustomStringBuffer();
str.appendWithTrailingSpace("string value");
(Although you may want to call your method something a little shorter.)
Just add the space yourself, it's easy enough, as per your own example.
Another possibility is that StringBuilder objects return themselves when you call append, meaning you can do:
str.append("string value").append(" ");
Not quite as slick, but it is probably an easier solution than the + " " method.
Another possibility is to build a wrapper class, like PaddedStringBuilder, that provides the same methods but applies the padding you want, since you can't inherit.

Categories

Resources