Android switch by values from strings.xml - java

I'm new with Android and want to understand another one moment. I've got a strings.xml, which values I use in activity.xml. How use this values from JAva code in switch block?
private void gotoActivity(CharSequence text) {
switch (text.toString()) {
case getString(R.string.title_activity_first):
break;
case RADIO_BUTTON_SECCOND:
break;
}
}
Not compiles 'cos of "Constant expression required". But the main benefit of strings.xml - is string constants in one place.
Help plz.

Unfortunately you cannot use resource string in switch-case. You have two options. Choose anyone...
use static final String in your activity.
Example: Initialize the strings
public static final String TITLE_ACTIVITY_FIRST = "activity_title";
public static final String RADIO_BUTTON_SECCOND = "radio_button_second";
Then you can use the TITLE_ACTIVITY_FIRST in switch case. like,
switch(text.toString()){
case TITLE_ACTIVITY_FIRST: break;
case RADIO_BUTTON_SECOND: break;
}
No error will show!
use if-else. You can then use your resource strings.
Example:
if(text.toString().equals(getString(R.string.title_activity_first))){
//your code in case of 1st condition
}else if(text.toString().equals(getString(R.string.title_activity_second))){
//your code in case of 2nd condition
}
The second might look clumsy. But you wont have to change your code too much. Whereas the first one might look quite handy and you can easily modify later. Hope it helps!

You can not use getString(R.string.title_activity_first) since it returns a localised string from the application's package's default string table.So the result will be different based on the locale and hence it won't be a constant.You can not even get a particular local string using getString() method.Better to use a static final String filed instead.Please refer here

Related

Should I pre-initialize a variable that is overwritten in multiple branches?

There is a method:
private String myMethod(String gender)
{
String newString = "";
if(gender.equals("a"))
newString = internal.getValue();
else
newString = external.getValue();
return newString;
}
I refactored everything, but with one small change:
String newString; instead of: String newString = "";
Does this refactor improve the code? I know that String is null when we don't initialize it, but in this example it always will have value a from if or else. Does this refactor change anything?
To answer the direct question: there's no need to assign a value initially here; all branches of the code's execution will pan out to giving newString a value. Thus you don't need to initialize it at all. Otherwise, I would initialize to whatever you would want as a "default" value.
Instead of two returns or a branching statement to assign a variable, I would just return with a ternary:
private String myMethod(String gender) {
return gender.equals("a")
? internal.getValue()
: external.getValue();
}
Is it better to initialize String or to leave it as null?
Your premise is flawed: not initializing the String doesn't mean its value is null.
You are not allowed to use a local variable before it has been assigned, in order to avoid you accidentally using a value you didn't intend. As such, the value isn't "null", it's undefined (*).
This is called definite assignment checking, and is there to prevent certain types of bug. If you give the variable a value you don't need to give it, you disable this check, and so are open to the bugs the compiler was trying to protect you from.
For example, if the code looked like this:
private String myMethod(String gender)
{
String newString = "";
if(gender.equals("a"))
newString = internal.getValue();
else if (gender.equals("b");
newString = external.getValue();
// Oops! meant to check if gender.equals("c")
return newString;
}
you might have a bug, because there is a missing case that you haven't checked.
If you had explicitly assigned null to the variable, you would have much the same issue; but now your method would return null, and so possibly cause an NPE in the calling code.
If you had omitted the = "", the compiler would stop you using newString in the return.
(Assigning and reassigning the variable also means the variable would not be effectively final, so you would be unable to use it inside a lambda or anonymous class).
(*) This only applies to local variables, and final member/static variables. Class members do not have to be definitely assigned before use if they are not final, which is a rich seam for bugs, and a good reason to make class members final wherever possible. And, technically, final members are initialized to their type's default value first, so you can actually read them as null before they are initialized.
It's best to only initialize a String (or anything else) if there is a scenario in which the initial value is used.
In your case you have assigned newString to a string literal that serves no purpose but to confuse the reader.
It should be evident that the performance and functionality will not change in any relavent way.
My take on the shortest form without the terniary operator (which I think decreases readability) :
private String myMethod(String gender)
{
if(gender.equals("a"))
return internal.getValue();
return external.getValue();
}
I would probably have a full if {...} else {...} construct like the other answers in my own code.
Also not all debuggers can easily show what is being returned from a method as part of the normal flow, so it may be easier if the return value is captured in a variable and THEN returned (where the breakpoint can be put on the return statement)
You can make this string final and keep unassigned to be sure that all if branches assigns the value:
final String result;
if (condition1) {
result = "one";
} else if (condition2) {
result = "two";
} else {
result = "other";
}
return result;
With this approach compiler will check that result variable was assigned once in each branch. It may be helpful if you add one more condition branch, or if you try to overwrite variable by mistake - compiler will fail and show the error.
In your case (if else condition) there no need to initialize the String, you can simple put it as String newString; and that would be ok because either way, at the end it will have a different value.
private String myMethod(String gender)
{
String newString;
if(gender.equals("a"))
newString = internal.getValue();
else
newString = external.getValue();
// Missing return statement.
}
Also, I see that you have a function that returns a string. Assuming that the newString variable is what you will be returning, instead of creating a string variable you can simple return the string in the condition:
private String myMethod(String gender)
{
if(gender.equals("a"))
return internal.getValue();
else
return external.getValue();
}
My colleges are right, this can be done with the tenary operator.
In addition I thinks its very important to prevent NullPoiterExeptions as often as possible.
What if gender would be null? NullPointerException
I would switch "a" and gender like this:
private String myMethod(String gender) {
return "a".equals(gender)
? internal.getValue()
: external.getValue();
}
According to Java doc:
Default Values
It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type. Relying on such default values, however, is generally considered bad programming style.
Local variables are slightly different; the compiler never assigns a default value to an uninitialized local variable. If you cannot initialize your local variable where it is declared, make sure to assign it a value before you attempt to use it. Accessing an uninitialized local variable will result in a compile-time error.

Java String predefine

I'm sure this question has allready been answered somewhere, but I' ve searched for half an hour now and I'm running out of keywords, because I have absolutly no idea how to do this.
I have a constructor for a class like this
public MyClass (String name)
{}
what I want is to define Strings so that only those Strings can be entered.
I assume it has something to do with static final strings, but there is quite a lot to be found to those and I dont know how to narrow down the search. Please tell me how that thing I want to do is called, so that I can search for it.
Edit:
Example to what I want:
I want to somehow define a number of Strings. (Or do somethig else that has the same effect, as I said I dont know how to do it)
String one = "ExampleOne";
String two = "ExampleTwo";
so that when I call the constuctor
MyClass myClass = new MyClass("somethingElse");
the constructor wont take it. Or even better eclipse allready showing my what options I have like it does whit "Color. "
Yes you have right you can not override String class because it is final so simply you can create your own StringWrapper class that wraps string.
public class StringWrapper{
private String content;
public StringWrapper(String c){
content = c;
}
//all your methods and fields there, for example delegated methods
public String toString(){
return content.toString();
}
}
But Enum could be also used in your case then you define your Enum values
public enum Color {
WHITE, BLACK, RED, YELLOW, BLUE; //; is required here.
#Override public String toString() {
//only capitalize the first letter
String s = super.toString();
return s.substring(0, 1) + s.substring(1).toLowerCase();
}
}
public myClass (Color color)
{}
There are two ways you can acheive this, either use a enum as constructor parameter. The enum itself contains only the allowed values, which is what I would do, keep everythign nice an oop and you can add logic to enums at a later date.
Or alternatively you can just check if the constuctor paramters value is valid, by performing a comparison and throwing an exception if not in allowed values. Have a predfined list and then, myList.contains(myString) - throw exception if false.
What I want is to define String so that only those Strings can be entered
I think that what you are after are Enums.
Enums will allow you to define a range of values which you can then use. In the example I have linked, the developer can restrict the type of input that he/she will receive to the days of the week.
You can check it in constructor's body at runtime, or if you want to compile-time checks, then you can use enum type argument (enum is a predefined set of constants).
From what I understand it seems like you want to limit what the String can be.
You would do this by putting conditional statements inside the constructor to weed out any Strings you don't want to be entered that would either notify the user that it is an invalid string or throw an exception, and the remainder of the constructor would only be executed in an else statement once it has passed all the tests making sure it is a valid String

How to transform a If Construct in Java to a Switch Case with Strings or Enum Values?

I have a xml document, that is saved as a string in the variable xmlRequest. I want to check, if a specific xml element is available in this xml document. I have a solution like this, but this a bad solution I would think:
if (xmlRequest.contains("<Initial>") && xmlRequestBody.contains("</Initial>")) {
// do something specific for <Initial>
}
if (xmlRequest.contains("<Area>") && xmlRequestBody.contains("</Area>")) {
// do something for <Area>
}
if (xmlRequest.contains("<Circle>") && xmlRequestBody.contains("</Circle>")) {
// do something for <Circle>
}
An If Else construction is bad too, since the number of if cases can be grow up very high. I Think a switch case is the best way to solve this problem, but how can i build it, since a use boolean comparisons too.
In short: You can't use a switch case statement in this case as it can only check value equality.
Anyway you should look into Java XML parsing instead of doing it yourself.
It looks like you're using custom code to do XML parsing. That's not usually a good idea, it's better to use a parser. And with some parsers, your structure would change sufficiently that the question would become somewhat irrelevant.
But depending on the parser, the question about code structure (and in particular long lists of if or if...else if) may remain, so I'll address it:
if...else if is the correct construct here, unless it's possible for more than one of the conditions to be true at the same time and you want to do the work in each case. If so, what you have (if...if) is the correct construct.
switch isn't useful here unless the things you're testing are constants or enums. You're using contains, so that doesn't apply. Java doesn't allow expressions in the cases, they must be constants or enums (reference), so if...else if or if...if is the best you can do with the strings you're using.
Well, no, actually: You could (and if there are lots of these, as you say, probably should) refactor that code to use the command pattern and a loop, e.g. (pseudocode):
TagCommands[] commands = /* ...objects that have the tag name
and function to call... */;
for (TagCommands command : commands) {
if (command.matches(xmlRequest, xmlRequestBody) {
command.execute(/*...relevant args here...*/);
}
}
...where TagCommand looks vaguely like this:
interface TagCommand {
void setTag(String tag);
String getTag();
boolean matches(String request, String requestBody);
void execute(/*...relevant args here...*/);
}
...possibly with
abstract class TagCommandBase implements TagCommand {
private String tag;
TagCommandBase(String tag) {
this.setTag(tag);
}
void setTag(String tag) {
this.tag = tag;
}
String getTag() {
return this.tag;
}
boolean matches(String request, String requestBody) {
return request.contains("<" + this.getTag() + ">") &&
requestBody.contains("</" + this.getTag() + ">");
}
}
}
...and then you create your array of TagCommand using concrete implementatons of that per tag that implement execute (either declared classes, or anonymous classes).
You need to use at least Java 7 - see the section entitled "Using Strings in switch Statements" at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

Java : is there any way that this code can be improved

I have this coding inside my java file .
This code basically receives an int value and sets a char value for an Object
Student st = new Student();
if (attributeName.equals("Grade")) {
int sidevalue = Integer.parseInt(attribute.getValue()); // This returns an int value , and this value needs to be converted into char later as shown
if(sidevalue==1)
st.grade=1;
else if(sidevalue==2)
st.grade=2;
else if(sidevalue==5)
st.grade=3;
}
class Student
{
char grade ;
}
Integer.parseInt throws an exception, if the attribute name is not a number. Catch it and handle the error.
The Student class should be made public and go to a separate java file
The grade field should be an int (your passing numbers)
Alternatively - if you need to store chars, you may have to say st.grade = '1'; (to pass a '1' instead of a 0x01)
The grade field should be private, use getGrade and setGrade methods to read an write the property
I don't understand the meaning of "sidevalue" - if it does not have a well known meaning in the domains context, then consider renaming it.
The local variable st should be renamed to student
the if-else-if chain could be replaced by a switch-case statement.
You could use a map
Map<Integer, Integer> gradeMappings = new HashMap<Integer, Integer>();
gradeMappings.put(1,1);
gradeMappings.put(2,2);
gradeMappings.put(3,5);
if (attributeName.equals("Grade")) {
int sidevalue = Integer.parseInt(attribute.getValue());
st.grade = gradeMappings.get(sidevalue);
}
In real life, you'd want to add some exception checking for when the attribute value is not a key in the map. You could also make the default behaviour to use the parsed attribute value as the grade, and only override the value if an appropriate entry is present in the map.
A switch case check here statement could avoid multiple if else indentation!
switch(sidevalue){
case 1: st.grade = 1;
break;
case 2: st.grade = 2;
break;
case 5: st.grade = 3;
break;
default: break;
}
There is no significant execution difference in running between if-else and switch.
Observed differences may be due to the sample space of the particular code you are running.
In the little code snippet you provide there is not a best choice, except that switch statement provides improved readability.
Check these links for further details:
Is "else if" faster than "switch() case"?
if-else vs switch
When to use If-else if-else over switch statments and vice versa
Look into the control keyword switch. This will somewhat alleviate this style of coding.
The best way to improve this code is to write a test for it.
Problems at this stage: 'grade' should be private.
Grade is probably a first class object.
How do you plan to support other grades? Say 4 or 6? What happens if sidevalue comes back with invalid value?
Others have suggested minor syntax changes (which may be helpful), but I think you are best thinking about this in an object-oriented sense, encapsulating this logic into the student class itself, that way you will only need to write it once. If you need different logic for different scenarios you can always use inheritance and override setGrade.
Student st = new Student();
st.setGrade(Integer.parseInt(attribute.getValue()))
class Student{
private char grade ;
public setGrade(int sidevalue){
if(sidevalue==1)
grade=1;
else if(sidevalue==2)
grade=2;
else if(sidevalue==5)
grade=3;
else
throw new IllegalArgumentException();
}
public char getGrade(){
return grade;
}
}
If you have canonical String values stored in attribute.getValue() then you can remove integer parsing and simply compare string values
String sidevalue=attribute.getValue()
if(sidevalue=="1"){
}else if(sidevalue=="2"){
}...
Refer to String.intern method for more details. This will help improve performance of your program.
1) Start using coding formats. Its advisable to use objStudent rather than some 'st'.
2) There is no use of creating int sidevalue. Directly use a switch case as give below:
switch(Integer.parseInt(attribute.getValue()))
{
case 1:
----
.
.
.
and so on...
}

Java using contains function to match string object ignore capital case?

I want that the contain function should return true even if the following are in capital letters
List<String> pformats= Arrays.asList("odt","ott","oth","odm","sxw","stw","sxg","doc","dot","xml","docx","docm","dotx","dotm","doc","wpd","wps","rtf","txt","csv","sdw","sgl","vor","uot","uof","jtd","jtt","hwp","602","pdb","psw","ods","ots","sxc","stc","xls","xlw","xlt","xlsx","xlsm","xltx","xltm","xlsb","wk1","wks","123","dif","sdc","vor","dbf","slk","uos","pxl","wb2","odp","odg","otp","sxi","sti","ppt","pps","pot","pptx","pptm","potx","potm","sda","sdd","sdp","vor","uop","cgm","bmp","dxf","emf","eps","met","pbm","pct","pcd","pcx","pgm","plt","ppm","psd","ras","sda","sdd","sgf","sgv","svm","tgs","tif","tiff","vor","wmf","xbm","xpm","jpg","jpeg","gif","png","pdf","log");
if(pformats.contains(extension)){
// do stuff
}
A Set is a better choice for a lookup.
private static final Set<String> P_FORMATS = new HashSet<String>(Arrays.asList(
"odt,ott,oth,odm,sxw,stw,sxg,doc,dot,xml,docx,docm,dotx,dotm,doc,wpd,wps,rtf,txt,csv,sdw,sgl,vor,uot,uof,jtd,jtt,hwp,602,pdb,psw,ods,ots,sxc,stc,xls,xlw,xlt,xlsx,xlsm,xltx,xltm,xlsb,wk1,wks,123,dif,sdc,vor,dbf,slk,uos,pxl,wb2,odp,odg,otp,sxi,sti,ppt,pps,pot,pptx,pptm,potx,potm,sda,sdd,sdp,vor,uop,cgm,bmp,dxf,emf,eps,met,pbm,pct,pcd,pcx,pgm,plt,ppm,psd,ras,sda,sdd,sgf,sgv,svm,tgs,tif,tiff,vor,wmf,xbm,xpm,jpg,jpeg,gif,png,pdf,log".split(","));
if(P_FORMATS.contains(extension.toLowerCase())){
// do stuff
}
Short answer: Will not work. You can't overwrite the contains, BUT: You can us the following code:
List<String> pformats= Arrays.asList("odt","ott","oth","odm","sxw","stw","sxg","doc","dot","xml","docx","docm","dotx","dotm","doc","wpd","wps","rtf","txt","csv","sdw","sgl","vor","uot","uof","jtd","jtt","hwp","602","pdb","psw","ods","ots","sxc","stc","xls","xlw","xlt","xlsx","xlsm","xltx","xltm","xlsb","wk1","wks","123","dif","sdc","vor","dbf","slk","uos","pxl","wb2","odp","odg","otp","sxi","sti","ppt","pps","pot","pptx","pptm","potx","potm","sda","sdd","sdp","vor","uop","cgm","bmp","dxf","emf","eps","met","pbm","pct","pcd","pcx","pgm","plt","ppm","psd","ras","sda","sdd","sgf","sgv","svm","tgs","tif","tiff","vor","wmf","xbm","xpm","jpg","jpeg","gif","png","pdf","log");
if(pformats.contains(extension.toLowerCase())){
}
This will make you extension to lowercase, and if within your Array are all extensions are already lowerCase, than it'll wokk.
Convert your List of extensions into a regular expression, compile it with the CASE_INSENSITVE flag, and use that.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Foo {
public static void main(final String... args) {
final Pattern p = Pattern.compile("odt|ott|oth|odm|sxw|stw|sxg|doc|dot|xml|docx|docm|dotx|dotm|doc|wpd|wps|rtf|txt|csv|sdw|sgl|vor|uot|uof|jtd|jtt|hwp|602|pdb|psw|ods|ots|sxc|stc|xls|xlw|xlt|xlsx|xlsm|xltx|xltm|xlsb|wk1|wks|123|dif|sdc|vor|dbf|slk|uos|pxl|wb2|odp|odg|otp|sxi|sti|ppt|pps|pot|pptx|pptm|potx|potm|sda|sdd|sdp|vor|uop|cgm|bmp|dxf|emf|eps|met|pbm|pct|pcd|pcx|pgm|plt|ppm|psd|ras|sda|sdd|sgf|sgv|svm|tgs|tif|tiff|vor|wmf|xbm|xpm|jpg|jpeg|gif|png|pdf|log", Pattern.CASE_INSENSITIVE);
// Will be true
System.out.println(p.matcher("bmp").matches());
// Will be false
System.out.println(p.matcher("quasar").matches());
}
}
This would probably be easier to read/maintain if you build the regex programatically, but I've left that as an exercise to the reader.
How about:
extension.toLowerCase()
?
Although I'm not sure 100% sure what contains() method will do in this example. You might need to stick your extensions into a Set.
Edit: No it wont work as the contains method checks for the existence of a particular Object. Your string, even with the same value, is a different Object. So yes either a) override the contains method, e.g loop through the array and do a string comparison or b) simpler, use a Set.
Edit 2: Apparently it will work per comments below as ArrayList.contains() checks for equality (so you will get a string match), but this seems to disagree with the top voted answer that says it wont.
If all your formats are lower case, then toLowerCase combined with a HashSet is the preferred solution.
If your formats are in mixed case (and shall stay this way, as you are using them for other things, too) you need a real case-insensitive comparison.
Then a TreeSet (or other SortedSet) with a case insensitive collator as the comparator will do. (It is not as fast as a HashSet, but will still be faster then the ArrayList (except for really small lists).)
Alternatively a HashSet variant using a custom hashCode and equals (or simply a normal HashSet on wrapper objects with a case insensitive implementation of equals and hashCode) would do fine.
Add this extended List class:
private static class ListIgnoreCase<String> extends java.util.LinkedList {
public ListIgnoreCase(Collection<String> c) {
super();
addAll(c);
}
public boolean containsIgnoreCase(java.lang.String toSearch) {
for (Object element : this)
if (java.lang.String.valueOf(element).equalsIgnoreCase(toSearch))
return true;
return false;
}
}
Now you can call asList like this:
if(new ListIgnoreCase(Arrays.asList("odt","ott","oth","odm"))
.containtsIgnoreCase(extension)) {
...
You can use IteracleUtils and Predicate from collections4 (apache).
List<String> pformats= Arrays.asList("odt","ott","oth","odm","sxw","stw","sxg","doc","dot","xml","docx","docm","dotx","dotm","doc","wpd","wps","rtf","txt","csv","sdw","sgl","vor","uot","uof","jtd","jtt","hwp","602","pdb","psw","ods","ots","sxc","stc","xls","xlw","xlt","xlsx","xlsm","xltx","xltm","xlsb","wk1","wks","123","dif","sdc","vor","dbf","slk","uos","pxl","wb2","odp","odg","otp","sxi","sti","ppt","pps","pot","pptx","pptm","potx","potm","sda","sdd","sdp","vor","uop","cgm","bmp","dxf","emf","eps","met","pbm","pct","pcd","pcx","pgm","plt","ppm","psd","ras","sda","sdd","sgf","sgv","svm","tgs","tif","tiff","vor","wmf","xbm","xpm","jpg","jpeg","gif","png","pdf","log");
Predicate<String> predicate = (s) -> StringUtils.equalsIgnoreCase(s, "JPG");
if(IterableUtils.matchesAny(pformats, predicate))
// do stuff
}
org.apache.commons.collections4.IterableUtils

Categories

Resources