Convert single char in String to lower case - java

I like to 'guess' attribute names from getter methods. So 'getSomeAttribute' shall be converted to 'someAttribute'.
Usually I do something like
String attributeName = Character.toLowerCase(methodName.indexOf(3))
+ methodName.substring(4);
Pretty ugly, right? I usually hide it in a method, but does anybody know a better solution?

The uncapitalize method of Commons Lang shall help you, but I don't think your solution is so crude.

Have a look at the JavaBeans API:
BeanInfo info = Introspector.getBeanInfo(bean
.getClass(), Object.class);
for (PropertyDescriptor propertyDesc : info
.getPropertyDescriptors()) {
String name = propertyDesc.getName();
}
Also see decapitalize.

uncapitalize from commons lang would do it:
String attributeName = StringUtils.uncapitalize(methodName.substring(3));
I need commons lang a lot, but if you don't like that extra jar, you could copy the method. As you can see in it, they doin' it like you:
public static String uncapitalize(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
return new StringBuffer(strLen)
.append(Character.toLowerCase(str.charAt(0)))
.append(str.substring(1))
.toString();
}

Its worth remembering that;
not all getXXX methods are getters e.g. double getSqrt(double x), void getup().
methods which return boolean, start with is and don't take an argument can be a getter, e.g. boolean isActive().

Given a character buffer, you can apply the below code:
int i = 0;
for(char x : buffer) {
buffer[i] = Character.toLowerCase(x);
i++;
}
Tested and functions :)

Looks fine to me. Yes, it looks verbose, but consider what you're trying to do, and what another programmer would think if they were trying to understand what this code is trying to do. If anything, I'd make it longer, by adding what you're doing (guessing attribute names from getter methods) as a comment.

Related

How to convert a String which looks like an Array into an actual Object Array?

Since
public static String requestMethodExecution(String objectName, String className, String methodName, Object...
params) {
return String.format("%s,%s,%s,%s", objectName, className, methodName, Arrays.toString(params));
}
returns a String, and if you would, for example, call the method like this:
requestMethodExecution("foo","bar","fooBar",2.0,3.0,"Hello");
You'd get a String like this: foo,bar,fooBar,[2.0,3.0,Hello]
I would love to iterate over that Array, but I can't since it is a String.
Reason behind this is this method: (I just started with reflection, so I do not know how else to do it)
public static Class[] getParameterType(String ...params) throws ClassNotFoundException {
Class[] paramTypes = new Class[params.length];
for(int i=0; i<params.length;i++){
Class paramClass = Class.forName(params[i]);
if (paramClass == Double.class) {
paramTypes[i] = (double.class);
} else if (paramClass == Integer.class) {
paramTypes[i] = (int.class);
} else {
paramTypes[i] = paramClass;
}
}
return paramTypes;
}
So far I have only come up with a very dirty way:
public static String[] getParams(String message){
int indexOfParamStart = message.indexOf("[");
int indexOfParamEnd = message.indexOf("]")+1;
String[] splitMessage = message.substring(indexOfParamStart, indexOfParamEnd).replaceAll("\\[", "")
.replaceAll("]", "").replaceAll(" ","").split(",");
return splitMessage;
}
Edit: Thanks for looking into this! Since some of you are asking what I am trying to achieve, here is a bit more explanation:
I want to implement a simple request/reply protocol which allows remote method invocation (and I do not want to use java RMI...)
So I listen for requests whose structure can be seen at the requestMethodExecution example.
There I have all the relevant information to call the Method upon my class, so to invoke the method I need it's arguments (and their value) and I do not know how to access them from the given String.
The others are easy with Class c = Class.forName(className); etc..
Edit#2:
My question is not about a simple regex, so why close it? The title already states a different subject, I am getting a bit salty here...
See this this question for using RegEx to extract the array body from the outer string (by the square brackets), and then you can simply use String.split(",") to split the array body into array items.

Substituting multiple Strings in String

I know there are a lot of questions and answers related to similar questions but I couldn't find an answer to my question. This a small snippet of my code:
private String substitute(String text) {
List<Macro> macros = getMacros();
for (Macro macro : macros) {
text = StringUtils.replace(text, macro.getKey(), macro.getValue());
}
return text;
}
Would this be a good way to substitute multiple macros variables in a text String? This creates a new String object on every loop so I am wondering if there's a better way to do this. Ideally I would have used Apache Commons StrSubstitutor class but I can't because of the format of the tokens/macros (different formats and not between a fixed prefix/suffix). I also don't want to use Regex because of performance issues.
According to some coding rules at work I need to mark the argument as final. I wonder if that's indeed good practice here. I know that Strings are immutable and I know that whenever I call StringUtils.replace() it will return me a new String object. But I am wondering if the String argument here should be marked as final as suggested and in the method do something like this:
String result = text;
for (Macro macro : macros) {
result = StringUtils.replace(result, macro.getKey(), macro.getValue());
}
I just don't like this.
Any help would be appreciated. Thanks.
You can use apache velocity to replace a string with keys with the equivalent string with values.
Your concern seems to be valid. String is immutable so it creates multiple objects. You should you either use StringBuilder or StringBuffer.
I wrote a sample for you. Build from here
private static String substitute(String text) {
List<Macro> macros = getMacros();
StringBuffer st = new StringBuffer(text);
for (Macro macro : macros) {
int start = st.indexOf(macro.getKey());
if (start != -1) {
st.replace(start, start + macro.getKey().length(), macro.getValue());
}
}
return st.toString();
}
Cheers!!
If you have some concerns about performance you could use a StringBuilder, which allows you to declare the text param as final:
private String substitute(final String text) {
List<Macro> macros = getMacros();
StringBuilder stringBuilder=new StringBuilder(text);
for(Macro macro: macros) {
int index=stringBuilder.indexOf(macro.getKey());
if (index!=-1) {
stringBuilder.replace(index, index+macro.getKey().length(), macro.getValue());
}
}
return stringBuilder.toString();
}

Returning switch capable value based on String

Not sure how I'm going to attack this.
Basically what I have is input of varying length, one or multiple times, that will cause an action. It being from typed input, file etc.
I have no idea on by what and how to tackle this. Would it be best to have a function returning an int that correspond to an public static final int FOO = 1;, an enum, an other way?
What I have as of now is a series of if statements as in:
if (str.equals("foo") || str.equals("F")) {
blah;
} else if (str.equals("beach")) {
more blah;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
class Mother
{
HappyCamping() {
switch (ValInput(str)) {
case FOO: do fo; break;
case BAR: do bar; break;
case BAZ: do fo bar: break
...
}
private enum ValInput(String str)
{
FOO("foo"), BAR("bar"), BAZ("baz");
private int value;
private ValInput(String str) {
if (str.equals("blah"))
this.value = 1;
...
}
}
}
Point being having a cleaner approach and separate out the "parsing" from the main routine. What would be a good way here?
One approach would be to write a parser that returns tokens. The tokens could be represented by ints or Enums. That modularizes your code in a way you suggest you want.
The other way is to use enums.
public enum Token {
FOO("foo", "f"),
BAR("bar", "b");
private String keyword;
private String abbreviation;
private Token(String keyword, String abbreviation) {
this.keyword = keyword;
this.abbreviation = abbreviation;
}
public String getKeyword() {
return this.keyword;
}
public String getAbbreviation() {
return this.abbreviation;
}
public static Token valueOf(String s) {
for (Token token : values()) {
if (token.getKeyword().equals(s) || token.getAbbreviation().equals(s)) {
return token;
}
}
throw new IllegalArgumentException("No such keyword: " + s);
}
}
Then you can do something like:
switch (Token.valueOf(inputString)) {
case BAR : doBarStuff(); return;
case FOO : doFooStuff(); return;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
Then go learn how enum works. Don't avoid a feature that may solve your problem just because it has more features. Chances are your design will want to make use of Java-style enums if you want a fixed set of actions.
enum Action { CLICK("click"), CLEAR("erase"); }
etc. is a good start.
Java (I think since 6, possibly 7) also supports switch taking strings instead of integer or enum values.
Not sure that I understand the entire problem, but you can convert a string to an enum easily in Java.
If the entry strings are limited and predefined, and you want to parse it as an enum using
EnumType.valueOf("foo")
I recommend reading on Java enums, they are quite powerful compared to C enums.
In Java 7 you can use String in a switch expression. Refer to this article:
switch (str) {
case "blah":
// some action
break;
case "beach":
// another blah
break;
default:
// default action
break;
}
Your if statements seems the most logical way to tackle this problem. No need to make your life complex, just keep it simple. Any other method has trade offs and complexity.
Consider using a Map and the command pattern as shown here. You can hide all map a keyword to functionality and never have to use an if or switch.

Loop for Enums in Java

I have some enums like this:
public enum Classification {
UNKNOWN("Unknown"),
DELETION("Deletion"),
DUPLICATION("Duplication"), ....
but some of them have like 20 members, so currently in code I deal with them with huge if/else blocks like this:
int classification= rs.getInt("classification");
if (classification == Classification.UNKNOWN.ordinal()) {
variant.setClassification(Classification.UNKNOWN);
} else if (classification == Classification.DELETION.ordinal()) {
variant.setClassification(Classification.DELETION);
( rs is from JDBC tho).
Does Java have a better way this these big if/else blocks to do what I am doing? some sorting of looping through it?
You could use Enum#values() to get all enum values in an array. The ordinal maps 1:1 to the array index. Add the following method fo your Classification enum:
public static Classification of(int ordinal) {
if (0 <= ordinal && ordinal < values().length) {
return values()[ordinal];
}
throw new IllegalArgumentException("Invalid ordinal " + ordinal);
}
and use it as follows
Classification classification = Classification.of(rs.getInt("classification"));
// ...
However, using enum's ordinal for this is not the best practice. What if some developer rearranges the enum's values or adds/removes values? Even the javadoc warns that it has usually no use for developers. Rather give each enum value a fixed identifier. You could pass it in as an additional argument of the enum constructor argument. You could even use enum's String representation for that.
UNKNOWN(1, "Unknown"),
DELETION(2, "Deletion"),
DUPLICATION(3, "Duplication"),
// ...
Then use that value for DB instead and modify the of() method to walk through them in a foreach loop:
public static Classification of(int id) {
for (Classification classification : values()) {
if (classification.id == id) {
return classification;
}
}
throw new IllegalArgumentException("Invalid id " + id);
}
If the db value is the ordinal of the Enum then:
int classification= rs.getInt("classification");
variant.setClassification(Classification.values()[classification]);
I'll leave bounds checking as an exercise for the reader.
You can loop through an enumeration’s values via the object the someEnum.values() method returns:
for (Classification clz : Classification.values()) doSomethingWith(clz);
found here
I don’t know how exactly I can help you, since i don’t know what rs.getInt(String) does.
It seems to give back an Integer representing a enum value of Classification, but why?
Use variant.setClassification(YourEnumClassHere.values()[classification]). Enum.values() returns an array of all the declared enums in that class.
Instead of storing ordinal, you can store the name and use the valueOf method to convert the String back to your Enum type.
If you willing and able to store a string representation (this is a good technique) of the ENUM in your database, see Reference from Gareth Davis in comments above. If you are unwilling and/or unable to store a string representation and must continue with an ordinal representation, I suggest that a Map is called for. Here is some example code:
public class EnumMap
{
private enum FistSounds
{
Blam, Kapow, Zowie, Biff;
private static Map<Integer, FistSounds> ordinalMap = new HashMap<Integer, FistSounds>();
static
{
ordinalMap.put(Blam.ordinal(), Blam);
ordinalMap.put(Kapow.ordinal(), Kapow);
ordinalMap.put(Zowie.ordinal(), Zowie);
ordinalMap.put(Biff.ordinal(), Biff);
}
public static final FistSounds getByOrdinal(final int enumIndex)
{
return ordinalMap.get(enumIndex);
}
}
public static void main(String[] args)
{
FistSounds fistSound;
for (int index = -1; index < 5; ++index)
{
fistSound = FistSounds.getByOrdinal(index);
System.out.print("Ordinal: ");
System.out.print(index);
System.out.print(", FistSound: ");
System.out.println(fistSound);
}
}
}
I'd recommend using a switch statement, if the logic to execute is different for each case....
do as #Gareth Davis instructs and then just have a switch statement and handle each case as required.
Enums are also eligible to be used in switch statements see here

Avoiding multiple If statements in Java

I've coded a method something like this. But I guess this should undergo refactoring.
Can any one suggest the best approach to avoid using this multiple if statements?
private String getMimeType(String fileName){
if(fileName == null) {
return "";
}
if(fileName.endsWith(".pdf")) {
return "application/pdf";
}
if(fileName.endsWith(".doc")) {
return "application/msword";
}
if(fileName.endsWith(".xls")) {
return "application/vnd.ms-excel";
}
if(fileName.endsWith(".xlw")) {
return "application/vnd.ms-excel";
}
if(fileName.endsWith(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if(fileName.endsWith(".mdb")) {
return "application/x-msaccess";
}
if(fileName.endsWith(".rtf")) {
return "application/rtf";
}
if(fileName.endsWith(".txt")) {
return "txt/plain";
}
if(fileName.endsWith(".htm") || fileName.endsWith(".html")) {
return "txt/html";
}
return "txt/plain";
}
I cannot use switch-case here as my 'condition' is a java.lang.String.
You can use a Map to hold your solutions:
Map<String,String> extensionToMimeType = new HashMap<String,String>();
extensionToMimeType.put("pdf", "application/pdf");
extensionToMimeType.put("doc", "application/msword");
// and the rest
int lastDot = fileName.lastIndexOf(".");
String mimeType;
if (lastDot == -1) {
mimeType = NO_EXTENSION_MIME_TYPE;
} else {
String extension = fileName.substring(lastDot+1);
mimeType = extensionToMimeType.getOrDefault(extension,
UNKNOWN_EXTENSION_MIME_TYPE);
}
For this code to work you'll need to have defined NO_EXTENSION_MIME_TYPE and UNKNOWN_EXTENSION_MIME_TYPE as in your class, somewhat like this:
private static final String NO_EXTENSION_MIME_TYPE = "application/octet-stream";
private static final String UNKNOWN_EXTENSION_MIME_TYPE = "text/plain";
Using a HashMap perhaps?
This way you could do myMap.get(mystr);
Command pattern is the way to go. Here is one example using java 8:
1. Define the interface:
public interface ExtensionHandler {
boolean isMatched(String fileName);
String handle(String fileName);
}
2. Implement the interface with each of the extension:
public class PdfHandler implements ExtensionHandler {
#Override
public boolean isMatched(String fileName) {
return fileName.endsWith(".pdf");
}
#Override
public String handle(String fileName) {
return "application/pdf";
}
}
and
public class TxtHandler implements ExtensionHandler {
#Override public boolean isMatched(String fileName) {
return fileName.endsWith(".txt");
}
#Override public String handle(String fileName) {
return "txt/plain";
}
}
and so on .....
3. Define the Client:
public class MimeTypeGetter {
private List<ExtensionHandler> extensionHandlers;
private ExtensionHandler plainTextHandler;
public MimeTypeGetter() {
extensionHandlers = new ArrayList<>();
extensionHandlers.add(new PdfHandler());
extensionHandlers.add(new DocHandler());
extensionHandlers.add(new XlsHandler());
// and so on
plainTextHandler = new PlainTextHandler();
extensionHandlers.add(plainTextHandler);
}
public String getMimeType(String fileExtension) {
return extensionHandlers.stream()
.filter(handler -> handler.isMatched(fileExtension))
.findFirst()
.orElse(plainTextHandler)
.handle(fileExtension);
}
}
4. And this is the sample result:
public static void main(String[] args) {
MimeTypeGetter mimeTypeGetter = new MimeTypeGetter();
System.out.println(mimeTypeGetter.getMimeType("test.pdf")); // application/pdf
System.out.println(mimeTypeGetter.getMimeType("hello.txt")); // txt/plain
System.out.println(mimeTypeGetter.getMimeType("my presentation.ppt")); // "application/vnd.ms-powerpoint"
}
Personally I don't have problems with the if statements. The code is readable, it took just milliseconds to understand what you're doing. It's a private method anyway and if the list of mime types is static then there's no urgent need to move the mapping to a properties file and use a lookup table (map). Map would reduce lines of code, but to understand the code, then you're forced to read the code and the implementation of the mapping - either a static initializer or an external file.
You could change the code a bit and use an enum:
private enum FileExtension { NONE, DEFAULT, PDF, DOC, XLS /* ... */ }
private String getMimeType(String fileName){
String mimeType = null;
FileExtension fileNameExtension = getFileNameExtension(fileName);
switch(fileNameExtension) {
case NONE:
return "";
case PDF:
return "application/pdf";
// ...
case DEFAULT:
return "txt/plain";
}
throw new RuntimeException("Unhandled FileExtension detected");
}
The getFileNameExtension(String fileName) method will just return the fitting enum value for the fileName, FileExtension.NONE if fileName is empty (or null?) and FileExtension.DEFAULT if the file extension is not mapped to a mime type.
what about using a MIME detection library instead?
mime-util
mime4j
JMimeMagic library - Free. Uses file extension and magic headers to determine MIME type.
mime-util - Free. Uses file extension and magic headers to determine MIME type.
DROID (Digital Record Object Identification) - Free. Uses batch automation to detect MIME types.
Aperture Framework - Free. A framework for crawling external sources to identify MIME types.
(feel free to add more, there so many libraries..)
I consider your approach to be the best overall. This comes after having tested with a number of different approaches myself.
I see a number of huge benefits in your current approach, namely:
Easily readable and understandable by anyone (in my experience, medium-level programmers often underestimate this and usually prefer going with fancy-patterns which, in the end are not readable at all for the vast majority of programmers who do not know that specific pattern)
All the information is in one single place. As Andreas_D pointed out, hunting around files or classes is not a good option for someone that needs to fix a bug while you are on holiday!
Easily maintainable: I could "F3" (if you are Eclipse-ing) on the method and add a new content type in seconds without any worries of introducing bugs!
I can suggest a few things anyway:
This method is very general purpose:
Why should it be private?! This is a
public method of some utility/helper class!
Moreover it should be a static method!! You don't need anything
from the Object itself to perform
your job!
You could use indenting to make
things prettier and compact. I know
that indenting is some kind of
religion for the most of us, but I
think it should not be a strict rule;
it should be properly used to make
our code more readable and compact.
If this would be a config file you
would probably have something like:
pdf=application/pdf
doc=application/msword
You could have a very similar result with:
public static String getMimeType(String fileName){
if(fileName == null) return "";
if(fileName.endsWith(".pdf")) return "application/pdf";
if(fileName.endsWith(".doc")) return "application/msword";
if(fileName.endsWith(".xls")) return "application/vnd.ms-excel";
return "txt/plain";
}
This is also what a lot of the Map based implementations look like.
There is no way to evade that in general. In your case - if there is a set of allowed extensions - you could create an Enum, convert the extension to the Enum type via valueOf(), and then you can switch over your enum.
Easiest and shortest way for this particular problem would be using the builtin Java SE or EE methods.
Either in "plain vanilla" client application (which derives this information from the underlying platform):
String mimeType = URLConnection.guessContentTypeFromName(filename);
Or in a JSP/Servlet web application (which derives this information from the web.xml files):
String mimeType = getServletContext().getMimeType(filename);
I would do this by putting the associations in a map, and then using the map for lookup:
Map<String, String> map = new HashMap<String, String>();
map.put(".pdf", "application/pdf");
map.put(".doc", "application/msword");
// ... etc.
// For lookup:
private String getMimeType(String fileName) {
if (fileName == null || fileName.length() < 4) {
return null;
}
return map.get(fileName.substring(fileName.length() - 4));
}
Note that using the switch statements on strings is one of the proposed new features for the next version of Java; see this page for more details and an example of how that would look in Java 7:
switch (fileName.substring(fileName.length() - 4)) {
case ".pdf": return "application/pdf";
case ".doc": return "application/msword";
// ...
default: return null;
(edit: My solution assumes the file extension is always 3 letters; you'd have to change it slightly if it can be longer or shorter).
You can always use a Groovy class here as it allows for switch-case on Strings :)
Create an enum called MimeType with 2 String variables: extension and type. Create an appropriate constructor and pass in the ".xxx" and the "application/xxx" values. Create a method to do the lookup. You can use enums in switch.
Just to mention it: A direct equivalent to your code would not be using a map for direct lookup (since that would require each extension to have exactly 3 characters) but a for loop:
...
Map<String, String> extmap = GetExtensionMap();
for (Map.Entry<String,String> entry: extmap.entrySet())
if (fileName.endsWith(entry.getKey))
return entry.getValue();
...
This solution works with extensions of any length but is less performant than the hash lookup of course (and slightly less performant than the original solution)
The Algorithmic-Design-Guy solution
A more performant way would be to implement a tree structure starting with the last character of the extension and storing the appropriate MIME types at the respective nodes.
You could then walk down the tree starting with the last character of the file name. But this is probably an overkill ...
How about mapping the extensions to MIME types, then using a loop? Something like:
Map<String,String> suffixMappings = new HashMap<String,String>();
suffixMappings.put(".pdf", "application/pdf");
...
private String getMimeType(String fileName){
if (fileName == null) {
return "";
}
String suffix = fileName.substring(fileName.lastIndexOf('.'));
// If fileName might not have extension, check for that above!
String mimeType = suffixMappings.get(suffix);
return mimeType == null ? "text/plain" : mimeType;
}

Categories