String Utils join in not working as expected - java

I have a list of strings which is returned from a query in List A.
I am trying to use String Utils.join to combine the values in the list to a string separated by comma and in quotes. But it is not working as expected.
Values in abcList - [abc, cde, fgh]
abcList.addAll(jdbcTemplate.queryForList(abcSql, String.class));
String abc= StringUtils.join(abcList, "','");
abc = "'" +abc+ "'";
Expected output - 'abc', 'cde', 'fgh'
Actual output - 'abc, cde, fgh'
I am not sure what I am doing wrong here as I want to pass the values form the string abc into query with "IN" condition.

As alternative you can also use stream.Collectors.joining
List<String> myList = Arrays.asList("abc","def","ghi");
String joined = myList.stream().collect(Collectors.joining("','", "'", "'"));
System.out.println(joined);

If you are using Java 8 you can use the native method for joining strings.
List<String> list = <get a list of strings somehow>;
String joinedString = String.join("','", list);
See the String.join javadoc
Just as a hint for JDBC queries...you should use named parameters for inserting the values in your query instead of manually constructing the query string.
See this SO post for an example.

Related

String vs StringBuilder

I have a condition like :
public String createId(List<String> list)
{
String id="";
if(list.contains("name"))
id+="TEST VALUE NAME";
if(list.contains("age"))
id+="Test Value AGE";
.
.
. likewise many if condition
return id;
}
As per my understanding we should use StringBuilder in loop condition and String in simple concatenation. So here wanted to ask I should use String or StringBuilder? Kindly suggest
StringBuilder is the best for this scenario because it's mutable. the String is immutable so when you modify the string it creates a new object.
It seems that for the given task it would be better to get rid of the multiple duplicated if statements by defining a list of the keys to match the input list and use Stream API to generate the string id, e.g. Collectors.joining with delimiter or without the delimiter.
Assuming that there is a single rule to create a part of the id: append "Test Value " + key.toUpperCase(), the implementation may look as follows:
final List<String> keys = Arrays.asList(
"name", "age" /* and other needed keys*/
);
public String createId(List<String> list) {
return keys
.stream()
.filter(list::contains)
.map(String::toUpperCase)
.map(str -> "Test Value " + str)
.collect(Collectors.joining("_")); // or Collectors.joining()
}
System.out.println(createId(Arrays.asList("age", "name", "surname")));
// output: Test Value NAME_Test Value AGE
If custom parts should be provided for name, age, etc., a Map of matches should be prepared and used, also it may make sense to convert the input list into Set<String to facilitate look-ups:
final Map<String, String> keys = new LinkedHashMap<>(); {
// fill the map in special order
keys.put("name", "Name Part");
keys.put("age", "Test Age");
/* and other needed keys*/
}
public String createId(List<String> list) {
Set<String> words = new HashSet<>(list);
return keys.keySet()
.stream()
.filter(words::contains) // faster lookup O(1) at the cost of another collection
.map(keys::get)
.collect(Collectors.joining("_")); // or Collectors.joining()
}
System.out.println(createId(Arrays.asList("age", "surname", "name")));
// output: Name Part_Test Age
In general your understanding is correct about when to use String concatenation vs StringBuilder. The Java Language Specification says
To increase the performance of repeated string concatenation, a Java
compiler may use the StringBuffer class or a similar technique to
reduce the number of intermediate String objects that are created by
evaluation of an expression.
For the larger majority of cases you should use whichever method results in better readability and maintainability.

How transform a list of objects to a list of strings based on the value of a property in java?

Is there a way how to transform a list of objects to a list of strings based on the value of a property? I have an entity Tag
public class Tag {
private int tagID;
private String description;
}
I get a list of tags with their ids and descriptions:
[Tag [tagID=1, description=121], Tag [tagID=1, description=244], Tag [tagID=1, description=331], Tag [tagID=2, description=244], Tag [tagID=2, description=122]]
And what I need is:
List<String> output = ["121,244,331", "244,122"]
So far I put together this:
String description = tags.stream().map(Tag::getDescription).collect(Collectors.joining( ";" ));
outputting a result for one tag
String description = "121,244,331"
Of course, I could run it through a loop and append the result to an array, but I wondered if there is a more ellegant way - even a one-liner?
You can use Collectors.groupingBy to group by tag id and then join description using Collectors.joining
List<String> res = new ArrayList<>(tagList.stream().collect(
Collectors.groupingBy(Tag::getTagID,
Collectors.mapping(Tag::getDescription, Collectors.joining(",")))).values());
I think you are looking to:
List<String> result = tags.stream()
.collect(Collectors.groupingBy(Tag::getTagID))
.values()
.stream()
.map(t -> t.stream().map(Tag::getDescription).collect(Collectors.joining( ";" )))
.collect(Collectors.toList());
Output
[121;244;331, 244;122]

How to get data from raw query in spring boot?

I have a query:
Query q = em.createNativeQuery("select DISTINCT id, rating, random() as ordering FROM table\n" +
" WHERE id not in (1,2) ORDER BY ordering LIMIT 10");
List data = q.getResultList();
Every element of this list is array like object:
I want to retrieve that "8" and "16" and compose a comma separated string (to use it in my query in "not in" section in future):
for (Object x : data) {
System.out.println(Arrays.asList(x).get(0));
}
But it produces strings:
[Ljava.lang.Object;#ee93cd3
[Ljava.lang.Object;#62f3c3e1
I don't know how to get that IDs ("8" and "16")
1.I think this is what you are looking for...
Convert JPA query.getResultList() to MY Objects.
or
List<Object[]> rows = q.getResultList(); for (Object[] row : rows) { System.out.println(row[0]); }
in this line
List<Object[]> data = q.getResultList();
data is list of Object of form
[ [1,233, 0.000333], [1,233, 0.000333] ]
for (Object[] x : data) {
// x is [1,233, 0.000333]
System.out.println(x[0]);
}
If I understood it correctly, you are looking for comma separated string of ID's.
If so, then follow these steps might help you to solve the issue.
Create a constructor in table which has only one parameter ID. (If you want you can add more parameters as well but make sure the value which you want it must be in constructor as well as in query.)
Write sql query and execute it.
It returns result and gather it in List which contains the object of the table.
Get the string
dataList.stream().map(obj -> obj.getId()).collect(Collectors.joining(", "))
This will give you the comma separated string.

Best way to suffix value to a string if it matches a condition and generate a comma separated list of the values in a list

What is the best way to do the below in Java 8.
I have a list of ColumnInfo objects,
ColumnInfo CLASS has below members
String name
Class<?> type
Object value
I want to iterate list of ColumnInfo objects and if any of them is of type String.class I want to suffix "IS A STRING" to the column name , for other columns I want to return column name as is, the return value should be a comma separated string. The comma separated string should maintain the order of items as is in the incoming List of ColumnInfo objects.
So, if I have column info objects as below
{order_code , Integer.class, 10}
{order_city, String.class ,"france"}
{is_valid, Boolean.class, true}
expected output
order_code, order_city IS A STRING, is_valid
Below is my approach, Is there a better way to do this?
String commaSepStr = columnInfos.stream()
.map(f -> {
String retValue = isString(f)? f.getName()+ " IS A STRING" : f.getName();
return retValue;
}).collect(Collectors.joining(" ,")));
You may do it like so,
String resultStr = columnInfoList.stream()
.map(ci -> ci.getType() == String.class ? ci.getName() + " IS A STRING" : ci.getName())
.collect(Collectors.joining(", "));
You don't need to assign it to a variable and return. Rather you can directly return it. Also the implementation of the isString method seems not necessary to me since it can be done inline. So it is fair for me to keep this as the answer.

Try to convert Arraylist<LatLng> to string before insert to database

I try to insert my ArrayList<LatLng> list1 with a lot of values like this: (99.9999999,99.9999999) to table in database MySQL, exacly to 1 column, something like this:
row 1 (99.9999999,99.9999999)
row 2 (99.9999999,99.9999999)
row 3 (99.9999999,99.9999999)
... all to 1 column.
In my opinion, currently i have a good method for this:
String sql = "INSERT INTO table1 VALUES(";
for(String s : list1) {
sql = sql+"'"+s+"'";
}
sql = sql+")";
stmt.executeUpdate(sql);
but Android Studio underlines String s and says:
Incompatible types
Required: com.google.android.gms.maps.model.LatLng
Found: java.lang.String
In my opinion, Android Studio trying to say me: you need to convert all values from ArrayList<LatLng> list1 to String !
Is it possible to convert all values from my ArrayList in one method ?
Bad way of doing it:
You can convert your data to string the following way:
for(LatLng s : list1)
{
String sql = "INSERT INTO table1 VALUES('"+s+"');
stmt.executeUpdate(sql);
}
That is, you don't have to do anything specific to convert it. I'm assuming you have the method toString() implemented in your LatLng class to give objects of LatLng type a meaningful string representation.
Good way of doing it:
String sql = "INSERT INTO table1 VALUES(?)";
PreparedStatement stmt = dbConnection.prepareStatement(sql);
for(LatLng s : list1){
stmt.setString(1, s); // insert 's' in place of the 1st '?'
stmt.addBatch();
}
stmt.executeBatch();
In this last case you are preparing a batch of commands to send at once to your database. This is much better than sending many sql statements because you end up having a lot less overhead. Also, you're not concatenating the sql statement by yourself. You give the initial sql statement with a '?' placeholder and then you insert the values with 'setString()' or 'setInt()' or whatever the type is of what you want to insert.
The error is telling you that the ArrayList does not contain strings, not that you must convert to a string. You can not implicitly convert an array entry of type LatLng to a string as you have done.
Your for statement should be:
for(LatLng ll : list1)
You should store the LatLng value in a point datatype , assuming you are using PostgreSQL/PostGIS. As noted by #juergen d in your comments it's not a good practice to store a comma delimited string in a single column or quote the string yourself.
Here's a link explaining how to store the LatLng data as a Point in PostGIS. Alternatively, you could store the lat and lng separately in 'double precision' datatypes.
Use the toString method on the LatLng instances to convert them to strings.
Do not attempt to quote parameters in SQL queries yourself; use the API's support for placeholders for that purpose. Trying to quote strings yourself makes it trivial for attackers to destroy or manipulate your database to their own ends.

Categories

Resources