Ternary operator for strings - any nicer way? - java

I'm concerned about this construct:
String out = "Text " + (obj==null ? "" : obj.getStr()+" ") + "text continues.";
It works and all, but I think it's ugly. Maybe I'm just too picky..
Anyway, I'm asking, is there some nicer way to do this kind of stuff?Or is this the generally accepted technique?

Use a StringBuilder:
final StringBuilder sb = new StringBuilder("Text ");
if (obj != null)
sb.append(obj.getStr()).append(' ');
final String out = sb.append("text continues.").toString();
Also, why .getStr()? Doesn't obj implement .toString()?
Note that if obj did implement .toString(), you could do "better" than that using Guava's Joiner:
private static final Joiner JOINER = Joiner.on(" ").skipNulls();
//
final String out = JOINER.join("Text", obj, "text continues.");
Ultimately, though, that is a question of style.

Well you can separate out the logic from the format, to start with:
String out = String.format("Text %stextcontinues",
obj == null ? "" : obj.getStr() + " ");

I like it better because it is concise.
The other way is the plain old if-then-else:
String toAdd = "";
if(object != null) {
obj.getStr() + " ";
}
String out = "Text " + toAdd + "text continues.";

String out = "Text text continues.";
if (obj != null)
out = "Text " + obj.getStr() + " text continues.";

Related

Better string manipulation code

I'm looking for an efficient (one line) string manipulation code to achieve this, regex probably.
I have a string, for example, "Calvin" and I need to convert this to "/C/a/l/Calvin".
i.e. take first three characters, separate them using '/' and later append the original string.
This is the code I've come up with and its working fine, just looking for a better one.
String first = StringUtils.substring(prodName, 0, 1);
String second = StringUtils.substring(prodName, 1, 2);
String third = StringUtils.substring(prodName, 2, 3);
String prodPath = path + "/" + first + "/" + second + "/" + third + "/" + prodName + "/" ;
prodName.replaceAll("^(.)(.)(.).*", "/$1/$2/$3/$0")
What is the point of StringUtils.substring(prodName, 0, 1) when the built-in prodName.substring(0, 1) will do the same thing??
Anyway, assuming prodName is always at least 3 characters long (since you didn't give rules for expected output if it is not), this is the fastest way to do it:
String prodPath = path + '/' +
prodName.charAt(0) + '/' +
prodName.charAt(1) + '/' +
prodName.charAt(2) + '/' +
prodName + '/';
Normally, char + char is integer addition, not string concatenation, but since the first value is a String, and the + operator is left-associative, all + operators are string concatenations, not numeric additions.
How about using String.charAt
StringBuilder b = new StringBuilder (path);
b.append ('/').append (prodName.charAt (0))
.append ('/').append(prodName.charAt (1))
.append ('/').append(prodName.charAt (2))
.append ('/').append (prodName).append ('/');
Don't use regex for simple stuff like this. You may save a couple lines, but you loose a lot in readability. Regex usually take some time to understand when reading them.
String s = path;
for (int i = 0; i < 3; i++)
s += prodName.substring(i,i+1) + "/";
s += prodName
You can use MessageFormat.format()
MessageFormat.format("{0}/{1}/{2}/{3}/{4}/", baseDir, name.charAt(0), name.charAt(1), name.charAt(2), name);
imho i would wrap it for readability,
private String getProductionDirectoryPath(String baseDir, String name) {
return MessageFormat.format("{0}/{1}/{2}/{3}/{4}/", baseDir, name.charAt(0), name.charAt(1), name.charAt(2), name);
}
Positive look ahead can be used
public static void main(String[] args) {
String s = "Calvin";
System.out.println(s.replaceAll("(?=^(\\w)(\\w)(\\w))", "/$1/$2/$3/"));
}
O/P:
/C/a/l/Calvin
No use of a regex, but a simple split over nothing =)
String[] firstThree = prodName.split("");
String prodPath = path + "/" + firstThree[0] + "/" + firstThree[1] + "/" + firstThree[2] + "/" + prodName + "/";
Another approach is using charAt():
String prodPath = path + "/" + prodName.charAt(0) + "/" + prodName.charAt(1) + "/"+ prodName.charAt(2) + "/" + prodName + "/";
You said efficient but you maybe meant terse. I doubt either should be an objective, so you have a different problem.
Why do you care that this string transformation requires four lines of code? Are you concerned that something that in your mind is one operation ("create transformed string") is spread over four Java operations? You should extract the four lines of Java into their own method. Then, when you read the code where the operation is needed you have one conceptual operation ("create transformed string") corresponding to one Java operation (call a method). You could call the methid createTransformedString to make the code even clearer.
You can use String Builder:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 3; i++) {
sb.append("/").append(prodName.charAt(i));
}
sb.append('/').append(prodName);
Or you can put all the code in loop:
int size = 2;
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= size; i++) {
if (i == 0)
sb.append('/');
sb.append(prodName.charAt(i)).append("/");
if (i == size)
sb.append(prodName);
}

What's the best way to return concatenated Strings with checks for null or empty in Java?

I have two Strings, each one of them can be empty (blank or empty by StringUtils definition.) I need to display them in a concatenated fashion having a simple character in between, e.g. dash, comma, etc.
For example, a person's name consists of LastName and FirstName. PrintName method should print in this fashion:
case a: both not empty
print LastName + ", " FirstName
case b: FirstName is empty
print LastName
case c: LastName is empty
print FirstName
case d: both are empty
print empty string
This is just a simple exercise, but I'm curious if there's a most efficient method in Java that requires minimum variables/memory allocation, fewer lines of code, so on and so forth... My definition of efficiency is a bit vague so if you could write down why you think it's more efficient, that would be nice.
If it's just two strings, and they are empty, not null, I'd go with
System.out.println(
lastName
+ (( firstName.length() > 0 && lastName.length() > 0 ) ? ", " : "")
+ firstName
);
Explanation: the middle expression will be ", " only if both strings are non-empty.
In all other cases both the middle part and one or both of the others are empty. Thus, only the full side is printed.
If you want to go by StringUtils's definitions, the code is:
System.out.println(
StringUtils.stripToEmpty(lastName)
+ (( StringUtils.isNotBlank(firstName) && StringUtils.isNotBlank(lastName) ) ? ", " : "")
+ StringUtils.stripToEmpty(firstName)
);
You could design your pritning method like follows:
public class Main {
private final static Predicate<String> notEmpty = s -> s != null;
private final static Predicate<String> notBlank = s -> !s.equals("");
// ...
private static void printName(final String firstName, final String lastName) {
final boolean firstNameOk = notEmpty.and(notBlank).test(firstName);
final boolean lastNameOk = notEmpty.and(notBlank).test(lastName);
final StringBuilder result = new StringBuilder();
// Old version:
//result
// .append(lastNameOk ? lastName : "")
// .append(lastNameOk && firstNameOk ? ", " : "")
// .append(firstNameOk ? firstName : "");
// End of old Version:
// New version:
if (lastNameOk) {
result.append(lastName);
}
if (firstNameOk) {
if (lastNameOk) {
result.append(", ");
}
result.append(firstName);
}
// End of new version:
System.out.println(result);
}
}
Then some example calls:
public static void main(String[] args) {
printName("James", "Bond");
printName("James", null);
printName(null, "Bond");
printName(null, null);
}
Will print:
Bond, James
James
Bond
Only one boolean variable, but still four branches:
public void p(String f, String l) {
boolean e=l==null||l.isEmpty();
System.out.println(f==null||f.isEmpty()?e?"":l:e?f:f+", "+l);
}
This is surely not the best way and I would also recommend using Guava or another library like Apache commons.
return (firstName == null ? "" : firstname + ", " + lastName==null ? "" : lastName).replaceFirst("^, |, $","");
this will result in the firstname + ", " + lastname string, and in case the ", " string is at the beginning or the end of the string, it will be erased, therefore you get exactly what you want.
You can use apache commons api class to validate it in single line.
GenericValidator.isBlankOrNull(value);
For that you need to use apache commons jar and import this class
import org.apache.commons.validator.GenericValidator;
Try this one:
String LastName = "First";
String FirstName = "Last";
boolean cond1, cond2;
cond1 = FirstName == null || "".equals(FirstName);
cond2 = LastName == null || "".equals(LastName);
String DesiredName = (cond2 ? "" : LastName) +
((!cond2 && !cond1) ? ", " : "") +
(cond1 ? "" : FirstName);
System.out.println(DesiredName);
Use Google's guava and its Joiner method. It is the most elegant solution as far as I know.
https://code.google.com/p/guava-libraries/wiki/StringsExplained
Joiner joiner = Joiner.on(", ").skipNulls();
return joiner.join(firstName, lastName);
To skips nulls + empty strings, store firstName, lastName... in an array or list and then do
return Joiner.on(", ").join(Iterables.filter(listOfStrings, StringPredicates.notEmpty()));
You can look at the Joiner source code to see how its implemented. It is certainly not the most efficient but in this case the ignorable efficiency gain is worth trading off with code clarity and readability.
Clean, no extra conditions/libraries. This is of course specific to your requirement. You can use Guava's Joiner for more complex requirements.
public static void main(String[] args) throws Exception {
String firstName = "Stack";
String lastName = "Overflow";
System.out.println(printName(firstName, lastName));
}
private static String printName(String firstName, String lastName) {
StringBuilder buffer = new StringBuilder();
String cleanFirstName = avoidNull(firstName, "");
String cleanLastName = avoidNull(lastName, "");
if (!cleanLastName.isEmpty()) {
buffer.append(cleanLastName);
}
if (!cleanFirstName.isEmpty()) {
if (!cleanLastName.isEmpty()) {
buffer.append(", ");
}
buffer.append(cleanFirstName);
}
return buffer.toString();
}
private static String avoidNull(String str, String alternate) {
if (str == null || str.isEmpty()) {
return alternate;
}
return str;
}
You can remove the alternate parameter in the avoidNull() method if you don't want it.
private static String avoidNull(String str) {
return str == null ? "" : str;
}
I believe you shouldn't focus on performance this much, but on clean code.
If you have only two strings, you could create simple method as this one (I assume you are using Java 8).
public static String combine(String s1, String s2) {
StringJoiner sj = new StringJoiner(", ");
if (!StringUtils.isBlank(s1)) sj.add(s1);
if (!StringUtils.isBlank(s2)) sj.add(s2);
return sj.toString();
}
You can replace !StringUtils.isBlank(s1) with s1!=null %% !s1.trim().isEmpty()
If you want to create more generic method in which you could decide which delimiter to use, and which would be able to accept more than two Strings you could use something like
public static String joinWithourEmptyOrNull(String delimiter, String... words) {
StringJoiner sj = new StringJoiner(delimiter);
for (String s : words) {
if (!StringUtils.isBlank(s))
sj.add(s);
}
return sj.toString();
}
You can also rewrite this code into something more readable (at least for someone familiar with streams and lambdas - you don't have to be guru :D )
public static String joinWithourEmptyOrNull(String delimiter, String... words) {
return Arrays.stream(words)
.filter(s -> !StringUtils.isBlank(s))
.collect(Collectors.joining(delimiter));
}
Demo:
System.out.println(joinWithourEmptyOrNull(", ", "firstName", null, " ",
"secondName"));
result firstName, secondName
A simple "fix" would be
String toPrint = "";
if(lastName.length() > 0 && firstName.length() > 0){
toPrint = lastName + ", " - firstName;
}else if(!lastName.length() > 0 && firstName.length() > 0){
toPrint = firstName;
}else if(lastName.length() > 0 && !firstName.length() > 0){
toPrint = lastName;
}
System.out.println(toPrint)

Optimize String += or Concat? [duplicate]

This question already has answers here:
String concatenation: concat() vs "+" operator
(12 answers)
Closed 9 years ago.
I am writing a file with possibly 1000 data points. I have classes for all of these and am currently writing all of the data at the end (the datapoints are taken at 1s intervals). What I am currently doing is written below, and it's very slow. Would I be better off changing how I am writing the string/bytes to the file? Or would I be better off writing this information to some file pointer as the application is running?
Btw, all of the things such as getAccuracy() and such are floats/ints (so it has to convert those also).
fileStr = "";
fileStr += "timestamp,Accuracy,Altitude,Latitude,Longitude,GPSSatelliteEntries\r\n";
for (Iterator<Entry> i = entries.iterator(); i.hasNext(); ) {
Entry item = i.next();
long ts = item.getTs();
DataEntry d = item.getD();
List<GPSSatelliteEntry> satellites = item.getG();
// write stuff
fileStr += ts + ",";
fileStr += d.getAccuracy() + "," + d.getAltitude() + "," + d.getLatittude() + "," + d.getLongitude() + ",";
fileStr += "[";
boolean entered = false;
for (Iterator<GPSSatelliteEntry> j = satellites.iterator(); j.hasNext(); ) {
GPSSatelliteEntry item2 = j.next();
entered = true;
fileStr += "(" + item2.getAzimuth() + "," + item2.getElevation() + "," + item2.getPrn() + "," + item2.getSnr() + "),";
}
// chop off extra ,
if (entered)
fileStr = fileStr.substring(0, fileStr.length() - 1);
fileStr += "]";
fileStr += "\r\n";
}
Everytime you have hard work with Strings, use StringBuilder or StringBuffer to achieve better performance .
Don't forget that String is immutable, and each time you modify String new instance will be created and it costs performance.
Most probably string buffer
A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified.
or go for string builder
StringBuilder stuff = new StringBuilder();
stuff.append("PUT YOUR STRINGS HERE");
stuff.append("PUT YOUR STRINGS HERE");
Then you can use 'stuff' to print the strings.
Put it in a loop and iterate over a large number with a timer to see the advantages, it's pretty interesting.

How to split String by taking space's in java

I know its very easy to split data in strings, but still i want guide to concate string,
my data is in the format. In my string the data is in the above format
104
inNetStandardGuest
windowsGuest
uestToolsTooOld
121
slesGuest
guestToolsTooOld
20569355609
Expected Output:
104,inNetStandardGuest,windowsGuest,uestToolsTooOld
121,slesGuest,guestToolsTooOld,20569355609
It's simply splitting and combining strings.
StringBuilder out = new StringBuilder();
for (String set : data.split("\n\n\n")) {
for (String line : set.split("\n")) {
out.append(line).append(',');
}
out.setCharAt(out.length(), '\n');
}
System.out.println(out);
With Guava's Splitter and Joiner:
final Iterable<String> lines = Splitter.on("\n\n\n").split(input);
for (final String line : lines) {
final Iterable<String> fields = Splitter.on("\n").split(line);
final String joined = Joiner.on(",").join(fields);
}
How about this?
String s = "104\n" +
"inNetStandardGuest\n" +
"windowsGuest\n" +
"uestToolsTooOld\n" +
"\n" +
"\n" +
"121\n" +
"slesGuest\n" +
"guestToolsTooOld\n" +
"20569355609\n";
System.out.println(s.replaceAll("(.)\\n","$1,")
.replaceAll(",,","\n")
.replaceAll(",\\n","\n"));
Probably not the most efficient way, though.
Buffered reader:
http://docs.oracle.com/javase/1.4.2/docs/api/java/io/BufferedReader.html
readLine() method:
http://docs.oracle.com/javase/1.4.2/docs/api/java/io/BufferedReader.html#readLine()
For example you read 4 lines
string outputLine = line1 + "," + line2 + "," + line3 + "," + line4;
Then read 2 lines and skip it.
If you don't know how to implement it using my advices, you should read
some basics tutorial.
Try this :
String str = "104\ninNetStandardGuest\nwindowsGuest\nuestToolsTooOld\n\n\n121\nslesGuest\nguestToolsTooOld\n20569355609";
str= str.replaceAll("\\s", ",").replaceAll(",,,", "\n");
System.out.println(str);
Output :
104,inNetStandardGuest,windowsGuest,uestToolsTooOld
121,slesGuest,guestToolsTooOld,20569355609

java regular expression

I have a string like this
STAR=20110209
00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209
00:01:01|STRT=20110209
00:01:01|STOP=20110209 00:01:01|
and i want to extract values of few of the keys here.
like whats the value of PNAM and SSTA.
I want a regular expression that can provide the values of few of the keys and keys can be in any order.
Would something like this work for you?
String str = "STAR=20110209 00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209 00:01:01|STRT=20110209 00:01:01|STOP=20110209 00:01:01";
String[] parts = str.split("\\|");
for (String part : parts)
{
String[] nameValue = part.split("=");
if (nameValue[0] == "somekey")
{
// ..
}
}
So, the way your problem is really isn't best solved with regular expressions. Instead, use split() like someone else has offered, but instead of having a crazy if loop, load everything into a map.
String str = "STAR=20110209 00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209 00:01:01|STRT=20110209 00:01:01|STOP=20110209 00:01:01";
String[] parts = str.split("|");
Map<String, String> properties = new HashMap<String, String>();
for (String part : parts) {
String[] nameValue = part.split("=");
properties.put(nameValue[0], nameValue[1]);
}
Then all you have to do is, properties.get("PNUM")
Use this Java code:
String str = "STAR=20110209 00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209 00:01:01|STRT=20110209 00:01:01|STOP=20110209 00:01:01|";
Pattern p = Pattern.compile("([^=]*)=([^|]*)\\|");
Matcher m = p.matcher(str);
String pnamVal = null, sstaVal = null;
while (m.find()) {
//System.out.println("Matched: " + m.group(1) + '=' + m.group(2));
if (m.group(1).equals("PNAM"))
pnamVal = m.group(2);
else if (m.group(1).equals("SSTA"))
sstaVal = m.group(2);
if (pnamVal != null && sstaVal != null)
break;
}
System.out.println("SSTA: " + sstaVal);
System.out.println("PNAM: " + pnamVal);
OUTPUT
SSTA: 20110209 00:01:01
PNAM: test_.xml

Categories