How I can create a complex string in Java efficiently? - java

I want to create a string which will look like the following:
"[{"product_id":"123","name":"stack"},{"product_id":"456","name":"overflow"}]"
I have the product_id and name in two arrays. How can I create the above type of string most efficiently?

This looks like JSON. You should use a JSON library.
There are plenty out there (see this page, scroll almost to the end), but
Gson (Sample Usage) or
Jackson (Sample Usage)
are the ones I'd use.

If it turns out you already have a List<ProductInformation>, then the default serialization with flexjson with an exclude will give you the string:
String jsonResult = new JSONSerializer().exclude("*.class").serialize(listOfProductInformation);
Regarding performance, your best bet is to use a good profiler to look at your overall application. This will identify your true hotspots/bottlenecks and if it turns out this serialization process is a hotspot, you can spend time tuning as #Ali mentions and running it back through the profiler or performance test harness to measure the impact.

You may want to have a look on the Java String Formatter:
http://download.oracle.com/javase/6/docs/api/java/util/Formatter.html

I'm assuming you have 2 arrays one containing and product_id and the other containing the values and both of these are in correct order.
I would create my own java object (POJO) that had two fields product_id and name then take your two arrays and create one array (or list) of POJOs each POJO containing the product_id and name. Then I would just use Jackson or Gson to create my JSON.
These libraries give you a JSON representation of a Java Objects, so in this case you will have to make sure that you have a list or even an array of objects which contain your product_id and name.
If you insist on doing it the hard-way (or no external library way), then I would create a template String and repeatedly call replace on it and add it to a StringBuffer. The StringBuffer is important if the string can be very large. Something like:
String template = "{\"product_id\":\"productId\",\"name\":\"productName\"}";
StringBuffer result = new StringBuffer("[");
for(int i=0; i<myProductArray.length; i++){
String temp = template.replace("productId",myProductArray[i]);
temp = temp.replace("productName",myNameArray[i]);
if(result.length() > 1)
result.append(",");
result.append(temp);
}
result.append("]");
return result.toString();
If you can replace the template String with a StringBuffer and manipulate that directly, it'll make a ton of difference performance wise for large Strings.
Regards,

Related

How to serialize a Java Map to PHP's array serialization format

I want to convert HashMap to a String, which corresponds to PHP's Array serialization format as described here:
http://php.net/manual/en/function.serialize.php
For example:
a:5:{s:5:"width";i:450;s:6:"height";i:352;s:4:"file";s:32:"2018/09/Sawtooth-Oak_450_a-1.jpg";s:5:"sizes";a:9:{s:9:"thumbnail";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}s:6:"medium";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-300x235.jpg";s:5:"width";i:300;s:6:"height";i:235;s:9:"mime-type";s:10:"image/jpeg";}s:32:"twentyseventeen-thumbnail-avatar";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-100x100.jpg";s:5:"width";i:100;s:6:"height";i:100;s:9:"mime-type";s:10:"image/jpeg";}s:21:"woocommerce_thumbnail";a:5:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-250x250.jpg";s:5:"width";i:250;s:6:"height";i:250;s:9:"mime-type";s:10:"image/jpeg";s:9:"uncropped";b:1;}s:18:"woocommerce_single";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-350x274.jpg";s:5:"width";i:350;s:6:"height";i:274;s:9:"mime-type";s:10:"image/jpeg";}s:29:"woocommerce_gallery_thumbnail";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-100x100.jpg";s:5:"width";i:100;s:6:"height";i:100;s:9:"mime-type";s:10:"image/jpeg";}s:12:"shop_catalog";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-250x250.jpg";s:5:"width";i:250;s:6:"height";i:250;s:9:"mime-type";s:10:"image/jpeg";}s:11:"shop_single";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-350x274.jpg";s:5:"width";i:350;s:6:"height";i:274;s:9:"mime-type";s:10:"image/jpeg";}s:14:"shop_thumbnail";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-100x100.jpg";s:5:"width";i:100;s:6:"height";i:100;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";a:12:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";s:0:"";s:11:"orientation";s:1:"0";s:8:"keywords";a:0:{}}}
I've started with the following test Map:
HashMap images2 = new HashMap();
images2.put("test1", "t1");
imagesArray.put("width", image.getWidth());
imagesArray.put("height", image.getHeight());
imagesArray.put("file", destinationFile);
imagesArray.put("sizes", images2);
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(imageMap);
System.out.println(jsonResult);
and the reasult is:
{
"file" : "/images/bolivia.jpg",
"sizes" : {
"test1" : "t1"
},
"width" : 450,
"height" : 450
}
Java does not use PHP's array serialization format so you have to write it yourself or change approach. You have the following options:
Iterate through the entries of your Map and for each entry output its type, s for String, i for int etc. together with the rest of the information (a String includes the length etc.)
From your PHP script, change approach and instead of reading PHP's array serialization use JSON. This is more of an open defacto standard, and you will be able to use other programming languages too since most languages support JSON or have easy libraries to do so these days.
Use a library which saves Java objects to PHP's serialization format. I would only recommend this option if you have no control on the PHP script and you absolutely cannot change it without breaking something else. If you do not own the PHP code, or you cannot maintain it effectively it may be a viable option. Do a quick search for Java libraries that do this such as this one:
https://github.com/marcospassos/java-php-serializer
Ok, i found solution - i will use
<!-- https://mvnrepository.com/artifact/com.xk72/pherialize -->
<dependency>
<groupId>com.xk72</groupId>
<artifactId>pherialize</artifactId>
<version>1.2.4</version>
</dependency>
Consider using Google's protobufs (prototype buffers). Protobufs are implemented in several languages, including Java, PHP, Python, C++, and so on.
It has the advantage of language independence--you define the buffer structure and compile the definition file into the language(s) of your choice.
Here's a trivial example of a protobuf with 2 fields, just to give an idea:
syntax = "proto2";
message CookiejarTransaction {
optional string action = 1; // Action is either "bake" or "eat"
optional uint32 amount = 2; // Amount is number of cookies
}
Disclaimer: I have no interest in Protobufs other than a happy developer who uses the tool.
https://developers.google.com/protocol-buffers/

Java concatenate strings vs static strings

I try to get a better understanding of Strings. I am basically making a program that requires a lot of strings. However, a lot of the strings are very, very similar and merely require a different word at the end of the string.
E.g.
String one = "I went to the store and bought milk"
String two = "I went to the store and bought eggs"
String three = "I went to the store and bought cheese"
So my question is, what approach would be best suited to take when dealing with strings? Would concatenating 2 strings together have any benefits over just having static strings in, say for example, performance or memory management?
E.g.
String one = "I went to the store and bought "
String two = "milk"
String three = "cheese"
String four = one + two
String five = one + three
I am just trying to figure out the most optimal way of dealing with all these strings. (If it helps to put a number of strings I am using, I currently have 50 but the number could surplus a huge amount)
As spooky has said the main concern with the code is readability. Unless you are working on a program for a phone you do not need to manage your resources. That being said, it really doesn't matter whether you create a lot of Strings that stand alone or concatenate a base String with the small piece that varies. You won't really notice better performance either way.
You may set the opening sentence in a string like this
String openingSentence = "I went to the store and bought";
and alternate defining each word alone, by defining one array of strings like the following ::
String[] thingsToBeBought = { "milk", "water", "cheese" .... };
then you can do foreach loop and concatenate each element in the array with the opening sentence.
In Java, if you concatenate two Strings (e.g. using '+') a new String is created, so the old memory needs to be garbage collected. If you want to concatenate strings, the correct way to do this is to use a StringBuilder or StringBuffer.
Given your comment about these strings really being URLs, you probably want to have a StringBuilder/StringBuffer that is the URL base, and then append the suffixes as needed.
Performance wise final static strings are always better as they are generated during compile time. Something like this
final static String s = "static string";
Non static strings and strings concatenated as shown in the other example are generated at runtime. So even though performance will hardly matter for such a small thing, The second example is not as good as the first one performance wise as in your code :
// not as good performance wise since they are generated at runtime
String four = one + two
String five = one + three
Since you are going to use this string as URL, I would recommend to use StringJoiner (in case your are using JAVA 8). It will be as efficient as StringBuilder (will not create a new string every time you perform concatenation) and will automatically add "/" between strings.
StringJoiner myJoiner = new StringJoiner("/")
There will be no discernable difference in performance, so the manner in which you go about this is more a matter of preference. I would likely declare the first part of the sentence as a String and store the individual purchase items in an array.
Example:
String action = "I went to the store and bought ";
String [] items = {"milk", "eggs", "cheese"};
for (int x = 0; x< items.length; x++){
System.out.println(action + items[x]);
}
Whether you declare every possible String or separate Strings to be concatenated isn't going to have any measurable impact on memory or performance in the example you give. In the extreme case of declaring truly large numbers of String literals, Java's native hash table of interned Strings will use more memory if you declare every possible String, because the table's cached values will be longer.
If you are concatenating more than 2 Strings using the + operator, you will be creating extra String objects to be GC'd. For example if you have Strings a = "1" and b = "2", and do String s = "s" + a + b;, Java will first create the String "s1" and then concatenate it to form a second String "s12". Avoid the intermediate String by using something like StringBuilder. (This wouldn't apply to compile-time declarations, but it would to runtime concatenations.)
If you happen to be formatting a String rather than simply concatenating, use a MessageFormat or String.format(). It's prettier and avoids the intermediate Strings created when using the + operator. So something like, String urlBase = "http://host/res?a=%s&b=%s"; String url = String.format(urlBase, a, b); where a and b are the query parameter String values.

Need a real simple way to read json value in java

I am currently writing an application in Java, and am struggling to extract the values from a String which is in a JSON format.
Could someone help me with the easiest, most simplest way to extract data from this string? I'd prefer not to use external library if at all possible.
{"exchange":{"status":"Enabled","message":"Broadband on Fibre Technology","exchange_code":"NIWBY","exchange_name":"WHITEABBEY"},"products":[{"name":"20CN ADSL Max","likely_down_speed":1.5,"likely_up_speed":0.15,"availability":true....
Could someone explain how I could return the "likely down speed" of "20CN ADSL Max for example?
Thanks
Currently , there is no way in Java to parse json without an external lib (or your own implementation).
The org.json library is a standard when working with JSON.
You can use this snippet along with the library to achieve what you asked:
JSONObject obj = new JSONObject(" .... ");
JSONArray arr = obj.getJSONArray("products");
for (int i = 0; i < arr.length(); i++) {
String name = arr.getJSONObject(i).getString("name");
if ( name.equals("20CN ADSL Max") ) {
String s = arr.getJSONObject(i).getString("likely down speed");
}
}
Hope this helps.
For sure it's possible to do the parsing yourself, but it'll be much faster if you rely upon an existing library such as org.json.
With that, you can easily convert the string into a JSON object and extract all the fields you need.
If an existing library is not an option, you'll need to build yourself the tree describing the object in order to extract the pair key-values
While this may seem like a very simple, straightforward task, it gets rather complicated rather quickly.
Check out the SO thread How to parse JSON in Java. There is unfortunately not a single, clear solution to that question as shown in that thread. But I guess the org.json library seems to be the most popular solution.
If your application needs to handle arbitrary JSON, I would advise against trying to build your own parser.
Whatever your objections are to using an external library, get over them.

How to avoid out of memory in StringBuilder or String in Java

I am getting a lot of data from a webservice containing xml entity references. While replacing those with the respective characters I am getting an out of memory error. Can anybody give an example of how to avoid that? I have been stuck for two days on this problem.
This is my code:
public String decodeXMLData(String s)
{
s = s.replaceAll(">",">");
System.out.println("string value is"+s);
s = s.replaceAll("<", "<");
System.out.println("string value1 is"+s);
s = s.replaceAll("&", "&");
s = s.replaceAll(""", "\"");
s = s.replaceAll("&apos;", "'");
s = s.replaceAll(" ", " ");
return s;
}
You should use a SAX parser, not parse it on your own.
Just look in to these resources, they have code samples too:
http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/
http://www.java-samples.com/showtutorial.php?tutorialid=152
http://www.totheriver.com/learn/xml/xmltutorial.html
Take a look at Apache Commons Lang | StringEscapeUtils.unescapeHtml.
Calling five times replaceAll, you are creating five new String objects. In total, you are working with six Strings. This is not an efficent way to XML-decode a string.
I reccommend you using a more robust implementation of XML-encoding/decoding methods, like those contained in Commons Lang libraries. In particular, StringEscapeUtils may help you to get your job done.
The method as shown would not be a source of out of memory errors (unless the string you are handling is as big as the remaining free heap).
What uou could be running into is the fact that String.substring() calls do not allocate a new string, but create a string object which re-uses the one that substring is called on. If your code exists of reading large buffers and creating strings from those buffers, you might need to use new String(str.substring(index)) to force reallocation of the string values into new small char arrays.
You can try increasing JVM memory, but that will only delay the inevitable if the problem is serious (i.e. if you're trying to claim gigabytes for example).
If you've got a single String that causes you to run out of memory trying to do this, it must be humongous :) Suggestion to use a SAX parser to handle it and print it in bits and pieces is a good one.
Or split it up into smaller bits yourself and send each of those to a routine that does what you want and discard the result afterwards.

Inserting a Java string in another string without concatenation? [duplicate]

This question already has answers here:
How to format strings in Java
(10 answers)
Closed 5 years ago.
Is there a more elegant way of doing this in Java?
String value1 = "Testing";
String test = "text goes here " + value1 + " more text";
Is it possible to put the variable directly in the string and have its value evaluated?
String test = String.format("test goes here %s more text", "Testing");
is the closest thing that you could write in Java
A more elegant way might be:
String value = "Testing";
String template = "text goes here %s more text";
String result = String.format(template, value);
Or alternatively using MessageFormat:
String template = "text goes here {0} more text";
String result = MessageFormat.format(template, value);
Note, if you're doing this for logging, then you can avoid the cost of performing this when the log line would be below the threshold. For example with SLFJ:
The following two lines will yield the exact same output. However, the second form will outperform the first form by a factor of at least 30, in case of a disabled logging statement.
logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);
Rythm a java template engine now released with an new feature called String interpolation mode which allows you do something like:
String result = Rythm.render("Hello #who!", "world");
The above case shows you can pass argument to template by position. Rythm also allows you to pass arguments by name:
Map<String, Object> args = new HashMap<String, Object>();
args.put("title", "Mr.");
args.put("name", "John");
String result = Rythm.render("Hello #title #name", args);
Links:
Check the full featured demonstration
read a brief introduction to Rythm
download the latest package or
fork it
It may be done by some template-libaries. But beware, Strings are immutable in Java. So in every case at some low level the concatenation will be done.
You'll always have to use some form of concatenation for this (assuming value1 isn't a constant like you show here).
The way you've written it will implicitly construct a StringBuilder and use it to concatenate the strings. Another method is String.format(String, Object...)1, which is analogous to sprintf from C. But even with format(), you can't avoid concatenation.
1 Yes, I know the anchor link is broken.
What you want is called String interpolation. It is not possible in Java, although JRuby, Groovy and probably other JVM languages do that.
Edit: as for elegance, you can use a StringBuffer or check the other poster's solution. But at the low level, this will always be concatenation, as the other posters said.
You can use this free library. It gives you sprintf like functionality. Or use String.format static method provided you use Java 5 or newer.
Why do you think string concatenation isn't elegant?
If all you are doing is simple concatenation, I'd argue that code readability is more important and I'd leave it like you have it. It's more readable than using a StringBuilder.
Performance won't be the problem that most people think it is.
Read this from CodingHorror
I would use a StringBuffer.. it's a common practise when you are dealing with strings. It may seem a bit when you see it for the first time, but you'll get quickly used to it..
String test = new StringBuffer("text goes here ").append(value1).append(" more text").toString();
Strings are immutable thus a new instance is created after every concatenation. This can cause performance issues when used in loops.
StringBuffer is mutable version of String - that means you can create one, modify it as you want and you have still only one instance. When desired you can get a String representation of the StringBuffer by calling it's toString() method.
The problem is not if this is an elegant way or not. The idea behind using a template system may be that you put your template in a normal text file and don't have to change java code if you change your message (or think about i18ln).

Categories