Java construrctor with string params - java

How can I extract attributes values from the string parameter ?
public class Pays{
public Pays(String paysDescriptions) {
//implementation
}
}
pays= new Pays("p1:Europe:France, p2:Amerique:Canada");
Edit:
I gave an answer below to people who have never used this type of constructor (like me :p ) and who may need some explanations.

You should try using String.split(String regex) API.
Break the parameter paysDescriptions using comma(,) as regex, then
Break the individual items using colon(:) as regex
Example:
public Pays(String paysDescriptions) {
String[] split_1 = paysDescriptions.split(",");
for (String split : split_1) {
String[] split_2 = split.split(":");
for (String sp : split_2) {
System.out.println(sp); // use sp.trim() if spaces after comma
// not required.
}
}
}

I misunderstand the logic because it's the first time I saw this kind of conctructor..I have only the unit test class and I should implement the code for the source one. So I've used a Map<String,String[]> to split parameters and then I can access to the various attributes of my class.
Map<String, String[]> paysMap = new HashMap<String, String[]>();
public Pays(String paysDescriptions) {
String s = paysDescriptions;
String[] pairs = s.split(",");
for (int i=0;i<pairs.length;i++) {
String pair = pairs[i];
String[] keyValue = pair.split(":");
paysMap.put(String.valueOf(keyValue[0]),new String[] {String.valueOf(keyValue[1]), String.valueOf(keyValue[2])});
}
}

Related

Java-Stream & Optional - Find a value that matches to a stream-element or provide a Default value

I have a Dictionary object which consists of several entries:
record Dictionary(String key, String value, String other) {};
I would like to replace words in the given String my a which are present as a "key" in one of the dictionaries with the corresponding value. I can achieve it like this, but I guess, there must be a better way to do this.
An example:
> Input: One <sup>a</sup> Two <sup>b</sup> Three <sup>D</sup> Four
> Output: One [a-value] Two [b-value] Three [D] Four
The code to be improved:
public class ReplaceStringWithDictionaryEntries {
public static void main(String[] args) {
List<Dictionary> dictionary = List.of(new Dictionary("a", "a-value", "a-other"),
new Dictionary("b", "b-value", "b-other"));
String theText = "One <sup>a</sup> Two <sup>b</sup> Three <sup>D</sup> Four";
Matcher matcher = Pattern.compile("<sup>([A-Za-z]+)</sup>").matcher(theText);
StringBuilder sb = new StringBuilder();
int matchLast = 0;
while (matcher.find()) {
sb.append(theText, matchLast, matcher.start());
Optional<Dictionary> dict = dictionary.stream().filter(f -> f.key().equals(matcher.group(1))).findFirst();
if (dict.isPresent()) {
sb.append("[").append(dict.get().value()).append("]");
} else {
sb.append("[").append(matcher.group(1)).append("]");
}
matchLast = matcher.end();
}
if (matchLast != 0) {
sb.append(theText.substring(matchLast));
}
System.out.println("Result: " + sb.toString());
}
}
Output:
Result: One [a-value] Two [b-value] Three [D] Four
Do you have a more elegant way to do this?
Since Java 9, Matcher#replaceAll can accept a callback function to return the replacement for each matched value.
String result = Pattern.compile("<sup>([A-Za-z]+)</sup>").matcher(theText)
.replaceAll(mr -> "[" + dictionary.stream().filter(f -> f.key().equals(mr.group(1)))
.findFirst().map(Dictionary::value)
.orElse(mr.group(1)) + "]");
Create a map from your list using key as key and value as value, use the Matcher#appendReplacement method to replace matches using the above map and calling Map.getOrDefault, use the group(1) value as default value. Use String#join to put the replacements in square braces
public static void main(String[] args) {
List<Dictionary> dictionary = List.of(
new Dictionary("a", "a-value", "a-other"),
new Dictionary("b", "b-value", "b-other"));
Map<String,String> myMap = dictionary.stream()
.collect(Collectors.toMap(Dictionary::key, Dictionary::value));
String theText = "One <sup>a</sup> Two <sup>b</sup> Three <sup>D</sup> Four";
Matcher matcher = Pattern.compile("<sup>([A-Za-z]+)</sup>").matcher(theText);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
matcher.appendReplacement(sb,
String.join("", "[", myMap.getOrDefault(matcher.group(1), matcher.group(1)), "]"));
}
matcher.appendTail(sb);
System.out.println(sb.toString());
}
record Dictionary( String key, String value, String other) {};
Map vs List
As #Chaosfire has pointed out in the comment, a Map is more suitable collection for the task than a List, because it eliminates the need of iterating over collection to access a particular element
Map<String, Dictionary> dictByKey = Map.of(
"a", new Dictionary("a", "a-value", "a-other"),
"b", new Dictionary("b", "b-value", "b-other")
);
And I would also recommend wrapping the Map with a class in order to provide continent access to the string-values of the dictionary, otherwise we are forced to check whether a dictionary returned from the map is not null and only then make a call to obtain the required value, which is inconvenient. The utility class can facilitate getting the target value in a single method call.
To avoid complicating the answer, I would not implement such a utility class, and for simplicity I'll go with a Map<String,String> (which basically would act as a utility class intended to act - providing the value within a single call).
public static final Map<String, String> dictByKey = Map.of(
"a", "a-value",
"b", "b-value"
);
Pattern.splitAsStream()
We can replace while-loop with a stream created via splitAsStream() .
In order to distinguish between string-values enclosed with tags <sup>text</sup> we can make use of the special constructs which are called Lookbehind (?<=</sup>) and Lookahead (?=<sup>).
(?<=foo) - matches a position that immediately precedes the foo.
(?=foo) - matches a position that immediately follows after the foo;
For more information, have a look at this tutorial
The pattern "(?=<sup>)|(?<=</sup>)" would match a position in the given string right before the opening tag and immediately after the closing tag. So when we apply this pattern splitting the string with splitAsStream(), it would produce a stream containing elements like "<sup>a</sup>" enclosed with tags, and plain string like "One", "Two", "Three".
Note that in order to reuse the pattern without recompiling, it can be declared on a class level:
public static final Pattern pattern = Pattern.compile("(?=<sup>)|(?<=</sup>)");
The final solution would result in lean and simple stream:
public static void foo(String text) {
String result = pattern.splitAsStream(text)
.map(str -> getValue(str)) // or MyClass::getValue
.collect(Collectors.joining());
System.out.println(result);
}
Instead of tackling conditional logic inside a lambda, it's often better to extract it into a separate method (sure, you can use a ternary operator and place this logic right inside the map operation in the stream if you wish instead of having this method, but it'll be a bit messy):
public static String getValue(String str) {
if (str.matches("<sup>\\p{Alpha}+</sup>")) {
String key = str.replaceAll("<sup>|</sup>", "");
return "[" + dictByKey.getOrDefault(key, key) + "]";
}
return str;
}
main()
public static void main(String[] args) {
foo("One <sup>a</sup> Two <sup>b</sup> Three <sup>D</sup> Four");
}
Output:
Result: One [a-value] Two [b-value] Three [D] Four
A link to Online Demo

How can I compare a String with an Array of Strings to get the Value from a Map?

I'm having a BiMap with a String as key and an array of Strings as value.
Now i'm trying to get with a single String (which is part of the value array) the key.
private static BiMap<String, String[]> map = ImmutableBiMap.<String, String[]>builder().build();
static {
map.put("000", new String[] {"CH", "CHE", "Switzerland"});
map.put("001", new String[] {"US", "USA", "United States of America"});
map.put("002", new String[] {"IT", "ITA", "Italy"});
}
And in the next method i'm trying to search with "CH" to get "000" (which does not work).
private static String getKey(Map<String,String[]> map, String find) {
Map<String[], String> inversedMap = map.inverse();
if(inversedMap.containsKey() {
return inversedMap.get(find);
}
return null;
}
Is there a way to 'find' the key like this, without that i need to search with an array like this: String[] find = new String[] {"CH", "CHE", "Switzerland"};
All the values and keys are unique, so there is expected only a single result.
And i'm searching always for the first value in the array, f.ex. "CH" or "US".
No, there is no way to find the key like you want. You have to either change the way you store the data to support all the different lookup method you need or go through all keys one by one (at which point making an inverse map makes no sense an you can just go through the Map entries).
A trivial approach would be a purpose built class that contains several maps.
In case you have a case to find smth. by value (not by key) then you could use for loop in case you do not worry about performance. Otherwise, you should wrap this BiMap with a wrapper and add addtional Map with val -> key:
public final class CountryCache {
private final Map<String, String[]> codeNames = new HashMap<>();
private final Map<String, String> nameCode = new HashMap<>();
{
codeNames.put("000", new String[] { "CH", "CHE", "Switzerland" });
codeNames.put("001", new String[] { "US", "USA", "United States of America" });
codeNames.put("002", new String[] { "IT", "ITA", "Italy" });
codeNames.forEach((code, names) -> Arrays.stream(names).forEach(name -> nameCode.put(name, code)));
}
private static final CountryCache INSTANCE = new CountryCache();
public static CountryCache getInstance() {
return INSTANCE;
}
private CountryCache() {
}
public String findByName(String name) {
return nameCode.get(name);
}
}

How to skip a particular string during string Joining in Java?

The source code I have uploaded it will join some strings value in a one line. I want a way that I can able to skip a particular string in time of string joining. Here i have stored the strings "This","is","a","test." in a string array. I want that in time of joining a particular string will be skipped. Like I want to skip "a". How can I able to do in Java? I want a generalized way that I will able to apply for any strings.
import java.util.StringJoiner;
public class Test_Joiner_for_seatPlan
{
public static void main(String[] args)
{
StringJoiner joinString = new StringJoiner( " ");
String[] testStringArray = {"This","is","a","test."};
String joinedString = null;
for(String s : testStringArray)
{
joinString.add(s);
}
joinedString = joinString.toString();
System.out.println("After Joining the String:\n"+joinedString);
}
}
Try with not equal condition with string. but its not feasible as its check everytime a value.
for(String s : testStringArray)
{
if(!s.equals("a")){
joinString.add(s);
}
}
If you have a list of values like a,b,c than you can do like this:
Set<String> exclude = new HashSet<String>(Arrays.asList("a","b","c"));
for(String s : testStringArray)
{
if(!exclude.contains(s)){
joinString.add(s);
}
}
Use Split method of string. It returns array. combine each of them to get the string.
for (String retval: Str.split("a")){
System.out.println(retval);
}
You can do it like this:
Code:
for(String s : testStringArray){
if(!s.equals("a")){ // replace 'a' with the required character or word you want to ignore
joinString.add(s);
}
}
One possible solution is to provide a Map or a List in which you store the String values that should get excluded in your join. Here is an example using a Map.
public static void main(String[] args) {
String[] testStringArray = {"This","is","a","test."};
Map<String, String> excludedStrings = createExcludingMap("a");
System.out.println("After Joining the String:\n" + join(testStringArray, excludedStrings));
}
private static String join(String[] inputData, Map<String, String> excludedStrings){
StringJoiner joinString = new StringJoiner( " ");
String joinedString = null;
for(String s : inputData)
{
if(excludedStrings.get(s) == null) // IF this return null, the String is not part of the Strings to be excluded, hence join the string
joinString.add(s);
}
joinedString = joinString.toString();
return joinString.toString();
}
private static Map<String, String> createExcludingMap(String... values) {
Map<String, String> output = new HashMap<>();
for(String s : values) { // Add each value to the map, with s as key
output.put(s, s);
}
return output;
}
output :/
After Joining the String:
This is test.
The StringJoiner is a utility class that was written specifically to be used with the new Java8 Stream functionality. The documentation of StringJoiner also refers to the Collectors.joining method. It creates the StringJoiner, and wraps it in an object suitable to pass to Stream.collect, actually a Collector.
As part of the Stream API we now also have direct support for filters, it is just a matter of employing the fluent API (fluent because we keep adding .something(...)) to add the .filter method.
You can use it as you did in your answer, but I would suggest doing it as follows:
import static java.util.stream.Collectors.joining;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class App {
public static String joinString(String [] sa,Predicate<String> filter) {
return Stream.of(sa).filter(filter).collect(joining(" "));
}
public static void main(String[] args) {
String[] testStringArray = new String [] {"This","is","a","test."};
System.out.println(joinString(testStringArray,(s)->!s.equals("a")));
}
}
I have deliberately broken it up by defining an extra method, so you can see the type of the filter passed along, exposing the Predicate. This would also make your function a little more generic making it work as you stated: 'I want a generalized way that I will able to apply for any strings'.
However if the Stream api is flexible enough that I do not see any need to abstract your own API for it. I suggest using it as-is:
import static java.util.stream.Collectors.joining;
import java.util.stream.Stream;
public class App {
public static void main(String[] args) {
System.out.println(
Stream
.of(new String [] {"This","is","a","test."})
.filter((s)->!s.equals("a"))
.collect(joining(" "))
);
}
}
I could have written most of it on a single line, but I like to break it up for readability.

Storing String on array java

I want to know if is it possible to Store a String variable on a String array?
I cant explain it well but here is what i do:
String st1 = "",st2 = "",st3 = "",st4 = "";
String[] str = {st1,st2,st3,st4};
Unfortunately when i use for loop the str gets the value of st1 and st2 and st3 ans st4 not the variable it self..
This is what i want to do exactly on my mind..
Whenever a have a String array for example:
String[] containsValue = { "hi", "hello", "there" };
String strHi, strHello, strThere;
String[] getContainsValue = { strHi, strHello, strThere };
for (int x = 0; x < getContainsValue.length; x++) {
getContainsValue[x] = containsValue[x];
}
The value of:
strHi = "hi"
strHello = "hello"
strThere = "there";
Basically i want to transfer that value of containsValue[] to 3 String which is strHi, strHello, strThere that are stored in getContainsValue[]. Then use for loop to asign value to them came from containsValue[].
Is this posible? If so then can you give me some format how to do it? thanks..
You can use Map<K,V>.
Map<String,String> map=new HashMap<String,String>();
map.put("strHi","hi");
map.put("strHello","hello");
map.put("strThere","there");
System.out.println(map.get("strHello"));
You can use enum class as the Array needed :
public enum EnumModifE {
str1("1"), str2("2"), str3("3");
String value;
EnumModifE(final String s) {
this.value = s;
}
public void setValue(final String s) {
this.value = s;
}
}
public class EnumModifM {
public static void main(final String[] args) {
for (final EnumModifE eme : EnumModifE.values()) {
System.out.println(eme + "\t" + eme.value);
}
EnumModifE.str1.setValue("Hello");
EnumModifE.str2.setValue("all");
EnumModifE.str3.setValue("[wo]men");
for (final EnumModifE eme : EnumModifE.values()) {
System.out.println(eme + "\t" + eme.value);
}
}
}
Output
str1 1
str2 2
str3 3
str1 Hello
str2 all
str3 [wo]men
See in Effective Java use of enum
The concept you are looking for is an "l-value". Briefly, when you are using a variable, are you using the value contained in the variable, or are you talking about the variable itself so that you can store something else into it? You want array that you're calling getContainsValue to have l-values for strHi, strHello, and strThere. Unfortunately there is no way to do this in Java. Initializing getContainsValue with strHi, strHello, and strThere uses the values of those variables, not their l-values.
Let's step back a bit and talk more about l-values vs values (sometimes, r-values). Consider the following code snippet:
int i = 17;
i = i + 1;
That second line is obviously not an equation; that would be nonsensical. Instead, it is an assignment. The meaning of i on the left and right sides of an assignment is different. On the right hand side, i means to use the value of that variable, in this case 17. On the left hand side, i means the variable itself, as a destination for storing values. Even though they look the same, the use of i on the right-hand side is for its value (more specifically, its r-value) and the use of i on the left-hand side is for its l-value.
In Java, there is no way to express the l-value of a variable in an array initializer, so what you're trying to do doesn't work. As others have pointed out, in other languages like C this is possible, by using the & (address-of) operator.
Since Java has limited ways of expressing l-values, usually the concept of "a place to store something into" is expressed via a reference to an object. One can then use this reference to store into fields of that object or to call methods on that object.
Suppose we have a class like this:
class MyContainer {
String str;
void setString(String s) { str = s; }
String getString() { return str; }
}
We could then rewrite your code to do something like the following:
String[] containsValue = { "hi", "hello", "there" };
MyContainer hiCont = new MyContainer();
MyContainer helloCont = new MyContainer();
MyContainer thereCont = new MyContainer();
MyContainer[] getContainsValue = { hiCont, helloCont, thereCont };
for (int x = 0; x < getContainsValue.length; x++) {
getContainsValue[x].setString(containsValue[x]);
}
Well you can use this.
Map<String,String> map = new HashMap<String,String>();
String[] str = {"hi","hello","there"};
for(int x = 0; x < str.lenght;x++){
map.put(str[x],"something you want to store");
}
Best thing may be use Map and store as key-Value pairs.
Map<String,String> myKVMap=new HashMap<String,String>();
myKVMap.put("strHi","value1");
myKVMap.put("strHello","value2");
myKVMap.put("strThere","value3");
This way you can eliminate all the variable name and value issues.
I think you should use Collection like Map.
Map is used to store data in the form of Key-Value Pairs.
Assume the Key is String and Value is a String too in your case.
Map<String, String> mp = new Map<String, String>();
mp.put("str1","Hi");
mp.put("str2","Hello");
You can iterate over it like the below.
for(Map.Entry<String, String> ar : mp.entrySet()){
System.out.println("Key: "+ar.getKey()+" :: "+"Value: "+ar.getValue());
}
Using a Map is a good idea. Another approach is to instantiate class variables, then assigning values will work.
public void testTransfer() {
String containsValue[] = { "hi", "hello", "there" };
Data strHi = new Data();
Data strHello = new Data();
Data strThere = new Data();
Data[] getContainsValue = { strHi, strHello, strThere };
for (int x = 0; x < getContainsValue.length; x++) {
getContainsValue[x].value = containsValue[x];
}
// print out
System.out.println(strHi.value);
System.out.println(strHello.value);
System.out.println(strThere.value);
}
class Data {
private String value;
}
There is no simple way to do what you want to do in Java. What you would need is the equivalent of the C / C++ address-of operator (&) ... or maybe Perl's ability to use a string as a variable name. Neither of these are supported in Java.
In theory, if the variables where instance variables, you could use reflection to access and update them. But the code to do this is messy, inefficient and fragile. And it won't work with local variables.
You would be better off looking for a different solution to the problem; e.g. use a Map, as other answers have suggested.
Or just settle for some clunky (but robust and reasonably efficient) code that uses a switch or series of if else if tests and the original variables.
If I am understanding your question, you want to be able to assign a regular String variable by looking it up in an array first and then making the assignment.
I agree with the other responders that if you are finding this approach necessary, it is probably ill-advised. But in the spirit of pure Q&A, here's the way:
interface StringAssigner {
void assign( String strValue );
}
// ...
String strHi, strHello, strThere;
StringAssigner[] asaGetContainsValue = {
new StringAssigner() { #Override public void assign( String strValue ) { strHi = strValue; } },
new StringAssigner() { #Override public void assign( String strValue ) { strHello = strValue; } },
new StringAssigner() { #Override public void assign( String strValue ) { strThere = strValue; } }
};
// ...
for (int x = 0; x < asaGetContainsValue.length; x++) {
asaGetContainsValue[x].assign( containsValue[x] );
}
Just say no.
I do agree with the other answers here that this feels like a workaround for something, but without knowing what that something is I cannot suggest anything better.
To answer the question, though: you could, however, wrap the string in simple class and store the object references of that class in your array and strHi, strHello, and strThere. This way even when you change the string property inside the class, the class object itself does not change so you will see the behavior you are looking for.
Or, you can use a HashMap as others have suggested. In your case if you still want to use the getContainsValue array, you can store the keys:
Map<String,String> map = new HashMap<String,String>();
map.put("strHi","");
map.put("strHello","");
map.put("strThere","");
String[] containsValue = { "hi", "hello", "there" };
String[] getContainsValue = { "strHi", "strHello", "strThere" };
for (int x = 0; x < getContainsValue.length; x++) {
map.put(getContainsValue[x], containsValue[x]);
}
Then, map.get("strHi") would return "hi" as you expect.

java parameter replacement in a String

I'ms looking for a way to replace my variables in a string by their value. Here is my string lookalike:
"cp $myfile1 $myfile2"
In fact, I looked the javadoc and it seems that I could use split() method from String class which is good but I have also seen an article on which it seems that it is possible to replace all my variables with regex and replaceAll() method. Unfortunately I didnt find any example on the last solution.
Is it possible to use replaceAll in my case (with an example)?
No, you can't use String.replaceAll in this case. (You could replace all $... substrings, but each replacement would depend on the actual variable being replaced.)
Here's an example that does a simultaneous replacement which depends on the substring being replaced:
import java.util.*;
import java.util.regex.*;
class Test {
public static void main(String[] args) {
Map<String, String> variables = new HashMap<String, String>() {{
put("myfile1", "/path/to/file1");
put("myfile2", "/path/to/file2");
}};
String input = "cp $myfile1 $myfile2";
// Create a matcher for pattern $\S+
Matcher m = Pattern.compile("\\$(\\S+)").matcher(input);
StringBuffer sb = new StringBuffer();
while (m.find())
m.appendReplacement(sb, variables.get(m.group(1)));
m.appendTail(sb);
System.out.println(sb.toString());
}
}
Output:
cp /path/to/file1 /path/to/file2
(adapted from over here: Replace multiple substrings at once)
I would stick to java and use
public void replace(String s, String placeholder, String value) {
return s.replace(placeholder, value);
}
You could even do multiple replacements with this approach:
public String replace(String s, Map<String, String> placeholderValueMap) {
Iterator<String> iter = placeholderValueMap.keySet().iterator();
while(iter.hasNext()) {
String key = iter.next();
String value = placeholderValueMap.get(key);
s = s.replace(key, value);
}
return s;
}
You could use it like this:
String yourString = "cp $myfile1 $myfile2";
Map<String, String> placeholderValueMap = new HashMap<String, String>();
placeholderValueMap.put("$myfile1", "fileOne");
placeholderValueMap.put("$myfile2", "fileTwo");
someClass.replace(yourString, placeholderValueMap);

Categories

Resources