Weird Apache Commons Lang StringUtils.join result - java

I'm getting weird results from Apache Commons Lang's StringUtils.join. Let's say I have:
List<String> values = new LinkedList<>();
values.add("120");
values.add("123456789");
values.add("9000");
values.add("en");
byte[] data = StringUtils.join(values, new char[] {1}).getBytes();
I expected to have 31323001313233343536373839013930303001656e, which is 120.123456789.9000.en, with . as 0x01. But what confuses me is that I'm getting
5b3132302c203132333435363738392c20393030302c20656e5d5b4340333664303437 instead, which converts to [120, 123456789, 9000, en][C#36d047. Is there a gotcha in the way I'm doing this that's causing the weird value?

You're using the following method:
public static <T> String join(T... elements)
Joins the elements of the provided array into a single String containing the provided list of elements.
No separator is added to the joined String. Null objects or empty strings within the array are represented by empty strings.
So this method calls toString() on the list of Strings and on the char array, and joins the results.
You want to pass a char or String separator as second argument instead:
StringUtils.join(values, '.').getBytes();

Related

Will the java Splitter result list ever be empty?

I am trying to split a string using Splitter class. For example:
List<String> resultList = Splitter.on("|").splitToList(stringToSplit);
My question is: can resultList ever be empty?
I cannot think of any cases that it would be empty. But if I directly use resultList.get(0), it seems buggy. Can I directly call resultList.get(0) without worries?
Well, that depends on how you configure your splitter instance. Here you have to very similar examples, both as input take an empty string.
First case uses "raw" splitter returns a list with only one element -- an empty string:
#Test
public void shouldReturnOneEmptyStringForRegularSplitter() {
//given
String input = "";
Splitter splitter = Splitter.on(',');
//when
List<String> result = splitter.splitToList(input);
//then
assertThat(result).containsOnly("");
}
In the second example the input is the same, but splitter is additionally configured to omit empty strings from a resulting list, which as a result returns an empty list:
#Test
public void shouldReturnOneEmptyStringForCustomized() {
//given
String input = "";
Splitter splitter = Splitter.on(',').omitEmptyStrings();
//when
List<String> result = splitter.splitToList(input);
//then
assertThat(result).isEmpty();
}
The behavior is documented:
For separator-based splitters that do not use omitEmptyStrings, an input string containing n occurrences of the separator naturally yields an iterable of size n + 1. So if the separator does not occur anywhere in the input, a single substring is returned containing the entire input. Consequently, all splitters split the empty string to [""] (note: even fixed-length splitters).
Splitter has couple more options you could configure and change the result base on that.
In your case, if you only use Splitter.on("|") without any additional options, you're guaranteed to always have at least one value in resulting list.
You can use this without checking if empty or not
resultList.stream().findFirst().orElseGet(null)
this will return the first object in your list otherwise it will return null
Base on code of the method Splitter#splitToList here,
It will return an empty ArrayList in case the given string could not be split
(In your case, it happens if the string does not contain "|")
407 public List<String> splitToList(CharSequence sequence) {
408 checkNotNull(sequence);
409
410 Iterator<String> iterator = splittingIterator(sequence);
411 List<String> result = new ArrayList<String>();
412
413 while (iterator.hasNext()) {
414 result.add(iterator.next());
415 }
416
417 return Collections.unmodifiableList(result);
418 }
Thus, you have to ensure the result is not empty or an IndexOutOfBoundsException would be thrown when calling resultList.get(0)
how about checking that stringToSplit contains "|" before call Splitter.on.splitToList

How to check String contains one of Strings in collection

I want to check if the target string contains string in collections. And match the longest one. E.g.
Target string: str = "eignelaiwgn"
Collection strings: eig, a, eb, eigne, eignep
The result needs to be eigne
First I thought HashMap, but it is not sorted. So I try to put collection strings into ArrayList, then sort the list with string length. Then use for each loop to check
if ( str.contains("eigne") )
This needs to loop list each time. Is there a better(faster) way to achieve this?
Seems pretty straightforward with streams:
String targetString = "eignelaiwgn";
Collection<String> collection = Arrays.asList("eig", "a", "eb", "eigne", "eignep");
Optional<String> longestMatch = collection.stream()
.filter(targetString::contains)
.max(Comparator.comparingInt(String::length));
longestMatch.ifPresent(System.out::println); // eigne
This reads as: For every string in the collection, check if the target string contains it. If true, return the string with the max length. (As the collection might be empty, or as no string in the collection might match the filter, max returns an Optional<String>).
You could use a TreeSet for the same.
String str = "eignelaiwgn";
// Assuming that the 'sub-strings' are stored in a list
List<String> myList = Arrays.asList("eig", "a", "eb", "eigne", "eignep");
// Create a TreeSet that sorts based on descending order of length
Set<String> treeSet = new TreeSet<>((a, b) -> b.length() - a.length());
treeSet.addAll(myList);
String containsSub = treeSet.stream().filter(e -> str.contains(e))
.findFirst()
.orElse("Not found");
Now we iterate over the TreeSet and find the first occurrence where the sub-string is present in the original string. Now since the TreeSet is sorted in descending order of length, iteration will start from the highest to the lowest.
you can use LevensteinDistance() method of StringUtils class in java which will tell you the number of changes needed to change one String into another.you can print string with minimum changes needed, which is your answer. see this document -> LevenshteinDistance
Also look for differences method for same class which will tell the difference between the two string.
You could use a suffix tree. Please follow this link:
https://www.geeksforgeeks.org/pattern-searching-using-suffix-tree/

Getting a char from a String

I have a String variable named List.I want to get the first char of the String which is in the List.
The problem is, that I cannot use the charAt() function on the List.
Here is my effort so far:
List<String> testList = new ArrayList<>();
testList.get(3).chatAt(0);
The code you have given should work (apart from the typo). It retrieves the 4th item in the list, which we know is a String because have defined the list as a list of Strings, and then gets the first character of that String. It will obviously break if there are not 4 things in the list, or if the String doesn't have any characters in it.
List<String> testList = new ArrayList<>();
testList.get(3).charAt(0);
You can make things a bit clearer by declaring the String as a variable before you call charAt on it.
String s = testList.get(3);
char c = s.charAt(0);
Methods get(String s)
is not available for arrays in Java, probably you confused it with methods of Java Collection Framework (list).
If you have an array of string you must first access on the element with array[i]
and after call the method charAt(int index).
Finally you must use array[i].charAt(index)
where i is the position in the array to the string that you search and index the index of character you must search in the string.

How to get a String value from a Map <String, String[] > in Java?

Basically, I have a Map<String, String[] > which contains a bunch of strings with a key. If I do String value = myMap.get("keyName");, this returns an Object rather than a string, and echoing it produces something like this: Ljava.lang.String;#1dfa166. Doing toString() doesn't help either.
What do I need to do to get the value as string:
My code looks like this:
String value ="" + request().body().asFormUrlEncoded().get("keyName");
Here the asFormUrlEncoded() method is what returns the Map
You're getting back an array of strings (second parameter to the generic Map as declared).
Change it to
String [] values = myMap.get( "keyName" );
and check values.length to see how many strings are in the array. If it's just one, you can just access it as values[0].
The reason it allows for a string array is because each key in the form could have multiple values, so it can't return a single string.

Referring a variable with a variable in java

I have got into a strange strange situation. I have 3 sets of strings like this
String set1q1="something"; //associated with randomNum=1
String set1q2="something";
String set1q3="something";
String set1q4="something";
... and so on
String set2q1="something"; //randomNum=2
String set2q2="something";
String set2q3="something";
String set2q4="something";
... and so on
String set3q1="something"; //randomNum=3
String set3q2="something";
String set3q3="something";
String set3q4="something";
... and so on
All these strings are initialised only once. Now in my program i generate a random number between 1-3. I converted this random number into a string and stored it into a string called set.
String set=randomNum.toString();
Now next intead of using "if-else" to send the data(if randomnum=1 send set1q1-5, if randomnum=2 then send set2q1-5), I want the appropriate data to be sent using one line.
For example: if random no 2 is chosen then set2q1 has to be sent where the "2" in between is has to be the value of "set"(which is defined above).
set"set"q1 //where set can be 1,2,3
Is there any way to do this?
What you are asking for is not possible;1 it's just not the way Java works. Why don't you just use an array, or a collection?
List<List<String>> allTheStrings = new ArrayList<List<String>>();
List<String> myStrings = null;
// Add a subset
myStrings = new ArrayList<String>();
myStrings.add("something");
myStrings.add("something");
myStrings.add("something");
allTheStrings.add(myStrings);
// Add another subset
myStrings = new ArrayList<String>();
myStrings.add("something");
myStrings.add("something");
myStrings.add("something");
allTheStrings.add(myStrings);
...
// Obtain one of the strings
String str = allTheStrings.get(1).get(2);
1. Except in the case where these variables are members of a class, in which case you could use reflection. But really, don't.
It is not possible. Local variable identifiers are converted to numbers (stack offsets) during compilation. But you should use arrays or collections anyway
Sounds like you want to index Strings by two indices. You should use a two-dimensional String array: String[][] strings. You may then access the desired string with strings[n][m]
Or you can achieve the same effect with a List<List<String>> strings if you need the dimensions of your 2D array to grow dynamically. You'd access the value you need with strings.get(n).get(m)
If you really want to access your strings by a composed name such as set2q1, then you just need a Map<String, String> strings. Then you'd access each value with strings.get("set" + m + "q" + n)
looks to me you should look into arrays, like this:
String[] strings = new String[]{"xxx", "yyy", "zzz"};
String string = strings[randomNumber];
create an arraylist instead and reference using the list index

Categories

Resources