How to prevent NullPointerException on substr()? - java

I have several substr() calls in my application. Is there any common library, eg by apache, that provides a substring utility which does not throw NPE if the value is null, but then just returns an empty string?
I know I could write it like this, but maybe there is already such in implementation?
public static String substr(String value, int idx) {
return value != null ? value.substr(idx) : "";
}

Take a look at the apache commons StringUtils.substring
An apache commons lang equivalent to your code is
StringUtils.defaultString(StringUtils.substring(value, idx));

I do not think you need a library for that. Just check against null and the length to avoid exceptions.
public static String substr(String value, int idx) {
if (value == null || value.isEmpty() || idx > value.length()) return "";
return value.substr(idx);
}

Simply check the length to avoid an exceptiom
public static String substr(int idx) {
if(value==null||idx>value.length){
return ""; // Exception avoided
}
return value.substr(idx) ;
}

You already coded it, and by definition you cannot make a call on a null object, so the library would do something like what you have written.

Anyway when you know what to do also it is quite simple.
You can put an utility class in your app with substr static method. Search and replace all the calls in the App with the one in utility class.

Related

Java Optionals to check input parameters

I am using to checking input parameters with the java boilerplate like this on the top of the method:
public static Boolean filesExist(String file1, String file2, String file3 ... ) {
if (file1 == null || file2 == null || file3 == null ||...) {
throw new IllegalArgumentException();
}
if (another_param == null) {
throw new NullPointerException();
}
}
However, I was reading up on Java 8's optionals and noticed we could do something like this instead:
Optional.ofNullable(file1).orElseThrow(IllegalArgumentException::new);
Optional.ofNullable(file2).orElseThrow(IllegalArgumentException::new);
Optional.ofNullable(another_param).orElseThrow(NullPointerException::new);
...
So my question is is there any downside of doing it the second way, I feel that it looks a bit cleaner to me.
For input validation, use Objects.requireNonNull instead:
public static Boolean filesExist(String file1, String file2, String file3 ... ) {
Objects.requireNonNull(file1);
Objects.requireNonNull(file2, "custom message");
}
It is more concise, communicates intention more clearly and does not create an additional Optional object. It throws a NullPointerException, though.
There is no downside of doing it this way and the code would work fine,but Optional were introduced to serve a different purpose.For example ,you can use Optional in the method signature in your interface in-order to clearly communicate your clients that the value returned by your method is "Optional".This way your clients don't have to do the guess work.
No, there is no downside of doing the second way. Both do the same thing but in a different way. Optional is a new feature which was added in Java 8.

How to set null value if String is empty?

Sometimes developers checks if Strings are null values, if yes, sets those Strings as empty value:
if (text == null) {
text = "";
}
What I want to do is to write opposite if statement:
if (text.isEmpty()) {
text = null;
}
But...first of all - I have to check (as usually) if this String is null to avoid NullPointerException, so right now it looks like this (very ugly but KISS):
if (!text == null) {
if (text.isEmpty()) {
text = null;
}
}
My class has several String fields and for all of them I have to prepare this solution.
Any basic ideas for more efficient code? Is it a good way to strech it to lambda expressions and iterate throught all String fields in this class?
Another alternative using Guava's emptyToNull:
text = Strings.emptyToNull(text);
I don't know the context in which you thought to mention streams relating to your question, but if you are open to the Apache StringUtils library, then one option would be to use the StringUtils#isEmpty() method:
if (StringUtils.isEmpty(text)) {
text = null;
}
In your example, if text is null then text.equals(null) will cause a NPE. You will want something like this:
if (text != null && text.isEmpty()) {
text = null;
}
If you want whitespace considered empty as well, you will want to call trim() before calling isEmpty():
if (text != null && text.trim().isEmpty()) {
text = null;
}
Since you want to reuse this code, it makes sense to make this a utility method that you can call from any class:
public static String setNullOnEmpty(final String text) {
return text != null && text.trim().isEmpty() ? null : text;
}
Don't use equals() to check if a string is null, but:
if (text == null)
So
if (text != null && text.isEmpty()) {
text = null;
}
This 1 line condition won't throw NPE if text is null because of short circuit evaluation.
You can do the same thing by using a one if statement like below,
if (text != null && text.isEmpty()) {
text = null;
}
I don't have a better answer to your exact problem than what has already been posted. However, I would strongly question why you would want to conflate empty strings and nulls into nulls. Nulls are generally a bad idea, a "billion-dollar mistake", to quote Tony Hoare, who himself invented null references. This blog post has some good arguments!
Have you considered going the opposite direction, converting any null strings to empty strings? That way you only have to deal with strings for most of your code and can stop worrying about null pointer exceptions.
Better yet, take a look at the Optional type, which represents an object that may or may not be present. This came about in Java 8 as a better way to represent absence than nulls. Here's a blog post that explains it.
We have a method in org.apache.commons.lang.StringUtils.trimToNull(s); and with this we can get the empty string value to null value
String text = StringUtils.trimToNull(emptyStringValue);

Wrong values from string empty test (java x kotlin)

I'm having a super weird behavior from a code that I was testing. The test I wrote was to see the behavior of the class if the Android returned an empty package name. After some debugging, I found this (consider that packageName is empty):
val resultFromKotlin = packageName.isNullOrEmpty()
val resultFromJava = StringUtils.isEmpty(packageName)
Is this expected? Can someone tell what the deal with this?
ps1.: In the picture above, Android Studio was complaining of isNullOrEmpty saying that could be simplified since packageName can't be null at that point.
ps2.: For references:
The StringUtils class is written in Java as follow:
public static boolean isEmpty(String str) {
return str == null || TextUtils.isEmpty(str.trim());
}
TextUtils is also from Java, but it's part of Android library:
public static boolean isEmpty(#Nullable CharSequence str) {
return str == null || str.length() == 0;
}
This is how kotlin implements it's extension method:
public inline fun CharSequence?.isNullOrEmpty(): Boolean {
contract {
returns(false) implies (this#isNullOrEmpty != null)
}
return this == null || this.length == 0
}
EDIT 08/11/2018:
Just for clarification, my problem is the wrong value returned from Java, not searching for an equivalence in the test, also:
This seems to be a problem with TextUtils when running tests.
If you are running unit tests, Android frameworks methods are mocked, and this one in particular returns false. Use instrumentation tests to run against a full Android runtime.
Here is where the issue is discussed.
I have tested manually by recreating the function, and it is returning true.
I would suggest using Apache Commons StringUtils implementation: StringUtils

Shortening if() with string.equals method

Is there any way to shorten this if() statement? To avoid repeating string.equals() somehow?
if (extension.equals("jpg") || extension.equals("JPG") || extension.equals("png") || extension.equals("PNG") || extension.equals("bmp") || extension.equals("BMP") || extension.equals("jpeg") || extension.equals("JPEG"))
{
tmp.setIcon(new ImageIcon(getClass().getResource("/menage/Resources/imageIco.png")));
}
To something looking similar to this :
if (extension.equals(("jpg")||("JPG")||("png")||("PNG")||("bmp")||("BMP")||("jpeg")||("JPEG")))
{
tmp.setIcon(new ImageIcon(getClass().getResource("/menage/Resources/imageIco.png"));)
}
I am aware that this question looks odd, however if() with such long conditions list is unclear and requires a lot of writing as well.
Start by changing equals(...) to equalsIgnoreCase(...).
Other options, create a HashSet of lower case Strings (or upper case if desired) with your image extensions and see if it contains your String of interest, changed to lower case:
if (imageExtSet.contains(myExtension.toLowerCase()) {
}
Here is short version with predefined image types:
Set<String> imgTypes = new HashSet<>() {{
add("jpg"); add("JPG");
add("png"); add("PNG");
add("bmp"); add("BMP");
add("jpeg"); add("JPEG");
}};
public boolean isImgType(String type) {
return imgTypes.contains(type);
}
You can keep all values in a list and then asks if contains. If it's only a one liner (you don't need to ask for this condition anywhere else), you can do:
if (Arrays.asList("jpg", "JPG", "png", "PNG", "bmp", "BMP", "jpeg", "JPEG").contains(extension))
You can of course save the list as an object and then anywhere you need to ask for this condition reference it.
Use HashSet
Like this
Set<String> extSet= new HashSet<String>();
// Add All in Lower case .. to save your efforts
extSet.add("jpg");
extSet.add("png");
//...etc etc
and just check if it is present in the Set
if(extSet.contains(extension==null?null:extension.toLowerCase()))
{
/// True
}
else
{
// False
}
One thing you can do to eliminate some checks, is to convert the string to lower case:
String ext = extension.toLowerCase();
Now you have shorten the statement to:
if (ext.equals("jpg") || ext.equals("png") || ext.equals("bmp") || ext.equals("jpeg"))
if (Arrays.asList("jpg", "jpeg", "png", "bmp").contains(extension.toLowerCase))
The other answers give lots of good low-level ideas, but the basic principle here is to prevent code reuse.
If you are doing this test more than once, create a method that does the test for you:
boolean isValidImageExtenstion(String extension) {
return (extension.equals("jpg") || extension.equals("JPG") ||
extension.equals("png") || extension.equals("PNG") ||
extension.equals("bmp") || extension.equals("BMP") ||
extension.equals("jpeg") || extension.equals("JPEG"));
}
Call the method whenever you need it. If you like you can use one of the approaches described in the other answers within the method, (and the 'ignore case' suggestion is certainly worth it) but the rest become less important now that you have prevented the code repetition. As a bonus, if you decide you want to support gif extensions you only have to make the change in one place.
The advantages of this approach over the others are that it is self-documenting. It's pretty obvious what the method does, and some of the other answers are pretty obscure.
If you are only doing this once, and don't intend to do it again, then you have already created working code, so don't waste your time modifying working code.
Add in some methods...
private static boolean isJpeg(String ext) {
return java.util.Arrays.asList("jpg", "jpeg").contains(ext.toLowerCase());
}
private static boolean isPng(String ext) {
return "png".equalsIgnoreCase(ext);
}
private static boolean isBmp(String ext) {
return "bmp".equalsIgnoreCase(ext);
}
And change it to...
else if (isJpeg(extension) || isPng(extension) || isBmp(extension))
{
tmp.setIcon(new ImageIcon(getClass().getResource("/menage/Resources/imageIco.png")));
}
The isJpeg will throw a NullPointerException if the extention is null, so ensure it's not null by adding extension != null || ... or something.
The above is slightly different for your specific case as it allows JpEg and all other mixed capitalizations to slip through. If you don't want that, use these. Plus, the below have the added benefit of never throwing NullPointerException if the extension is null.
private static boolean isJpeg(String ext) {
return java.util.Arrays.asList("jpg", "JPG", "jpeg", "JPEG").contains(ext);
}
private static boolean isPng(String ext) {
return java.util.Arrays.asList("png", "PNG").contains(ext);
}
private static boolean isBmp(String ext) {
return java.util.Arrays.asList("bmp", "BMP").contains(ext);
}

Converting String to Integers the safe way

I have a little method that amongst other things also converts a string into an integer. Since the string is a parameter of the method I want to make sure that that string is convertable. So I was just wondering what would be the safest and / or fastest way.
Version A: Just leave it as it is and take the risks (which I'm trying to avoid)
public static int stringToInt(String param) {
return Integer.valueOf(param);
}
(in terms of speed, what kind of difference would it make to version B and C?)
Version B: Catch the exception
public static int stringToInt(String param) {
try {
return Integer.valueOf(param);
} catch(NumberFormatException e) {
return -1;
}
}
Version C: Check each letter of the string to see, if it's a digit number or not
public static int stringToInt(String param) {
for(char c : param.toCharArray()) {
if(!Character.isDigit(c))
return -1;
}
return Integer.valueOf(param);
}
Note that the parameter has to be a positive number and the -1 is supposed to be the "error value" in my little program, in other words, all three versions of methods would work perfectally fine in my program.
I'm very open to any other suggestion you can give me, so feel free to create your own version, if you think yours is better.
Thank you very much for your support in advance.
Guava offers a utility method for this which returns null in case your String can't be parsed.
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/primitives/Ints.html#tryParse(java.lang.String)
Integer result = Ints.tryParse("1"); //returns 1
Integer result = Ints.tryParse("-1"); //returns -1
Integer result = Ints.tryParse("a"); //returns null
First, note that version C is not bulletproof: it would reject negative numbers, and would not catch numbers that are too large.
Version B is OK, yet it makes the caller change the coding style: rather than catching an error and processing it together with other errors, the caller would need to check for -1 all the time. This may be suboptimal in situations where you read multiple integers, but the error processing does not depend on which particular one has failed. In addition, new coders using your API may forget to check for -1, and use the error code inadvertently.
That's why I would stay with the first option: the code using version A would look instantly familiar to anyone who knows Java API, without the need to learn what happens inside your function.
I believe a modified B to throw an exception rather than returning -1 will be the best choice. It is good to throw the exception up to the level, where it can be processed to send the proper response to the user. Returning a value like -1 will make your code error prone. Assume that a different programmer is consuming your method and he/she just have the signature of your method. So it is not clear from the signature what he/she should code to handle an exception or error scenario. But if you throw the exception and add it to your method declaration then it will enable the other programmer to consume your method properly alongwith the required exception handling. For me this looks the best:
public static int stringToInt(String param) throws NumberFormatException {
try {
return Integer.valueOf(param);
} catch(NumberFormatException e) {
// return -1;
throw e;
}
}
Java 8 without any API:
Optional.ofNullable(strNum)
.map(Integer::valueOf).orElse(null);
public int stringToInt(String param) throws NumberFormatException {
Optional.ofNullable(param.replaceAll("\\s+", ""))
.map(Integer::valueOf).orElse(null);
/*
or
Optional.ofNullable(param.replaceAll(" ", ""))
.map(Integer::valueOf).orElse(null);
*/
}
use the replaceAll to replace white spaces the plus is cpu friendly even though seems not needed.
I used a combination of 2 answers to have it safe for nulls, empty or blank strings, and non numeric characters:
public static Integer safeStringToInt(String param) {
return Optional.ofNullable(param).map(Ints::tryParse).orElse(null);
}

Categories

Resources