Can IDEA do the same if/else suggestions as Resharper? - intellij-idea

IDEA's developers are also developers of Resharper. And I like the way Resharper suggests refactoring if/else.
Can IDEA do the same? this feature does not come by default.
EDIT
Here are some Resharper feature I am referring to:
Original code:
static public string ToNonNullString(this XmlAttribute attr)
{
if (attr != null)
return attr.Value;
else
return string.Empty;
}
Suggestion: remove redundant 'else' resulting in following:
static public string ToNonNullString(this XmlAttribute attr)
{
if (attr != null)
return attr.Value;
return string.Empty;
}
Source is here (
Code suggestions by Resharper making code less readable?).
I remember when I use Visual Studio with Resharper I get a lot of similar suggestions. Have not seen that in IDEA although I've been using it for 2 years.

Yes, it can. Using this Java code:
public class Test {
public String notNull(String str) {
if (str != null) {
return str;
} else {
return "empty";
}
}
}
I get the following suggestions when pressing Alt+Enter (Show intentions) on the else:
Selecting Remove Redundant 'else' converts the method to this:
public String notNull(String str) {
if (str != null) {
return str;
}
return "empty";
}
You can make IDEA report these automatically when you run an inspection. In Settings, go to Inspections, find Confusing 'else' branch in the Control flow-category. And check the Also report when there are no more statements after the 'if' statement.
Then running an inspection with that profile will show that you have a confusing else branch, and you can fix it with a click.

Related

How can I place `throw` inside helper-functions but still have null-safety?

I want to wrap a throw in a helper-function, for logging purposes and such.
private fun chooseEmailAddress(user: UserProfile): EmailAddress {
val emailAddress = user.emailAddresses.find {
true // some business logic
}
if (emailAddress == null) {
throwAndNotice(CustomError(
message = "No Email Address found.",
))
}
return emailAddress
}
private fun throwAndNotice(err: CustomError) {
NewRelic.noticeError(err)
throw err
}
The problem:kotlin complains about a type-mismatch:
Type mismatch.
Required: Email
Found: Email?
I guess the compiler does not know that throwAndNotice always throws. If I inline the throwAndNotice method, it works, but it leads to duplication in about a dozen methods.
Is there a way I can tell the compiler "the following method always throws"? Or is there another idiomatic way to deal with this issue? I don't want to resort to !!.
Make it return Nothing. This indicates that it will never return (either throw an exception or infinite loop):
private fun throwAndNotice(err: CustomError): Nothing {
NewRelic.noticeError(err)
throw err
}
You can see other examples of doing this in the standard library, like TODO() and error().
Side note (as mentioned by dey in the comments):
The null check can be rewritten using ?: like this:
return emailAddress ?: throwAndNotice(...)

Kotlin code duplicates a line in console on its own (looping through a function without taking user input)

Let me first put the code then explain:
fun main() {
loop# while (true){
println("Input the action (add, remove, import, export, ask, exit):")
val userInput = scanner.nextLine()
when (userInput){
"add" -> add()
"remove" -> remove()
"import" -> import()
"export" -> export()
"ask" -> ask()
"exit" -> {
print("Bye bye!")
break#loop
}
}
}
}
This is the main function where the user chooses what he wants to do. First he adds some cards that contain terms and definitions as pairs, but thats irrelevant. The problem lies after that, when using the function ask().
fun ask() {
println("How many times to ask?")
for (i in 0 until scanner.nextInt()){
for ((key,value) in map){
println("Print the definition of \u0022$key\u0022:")
var userAnswer = (readLine() ?: "exit").toString()
if (userAnswer == value) {
println("Correct answer.")
continue
}
else {
loop# for ((key2,value2) in map){
if(map.containsValue(userAnswer) && userAnswer == value2){
println("Wrong answer. The correct one is \u0022$value\u0022, you've just written the definition of \u0022$key2\u0022")
break#loop
}else if (!map.containsValue(userAnswer)) {
println("Wrong answer. The correct one is \u0022$value\u0022.")
break#loop
}
}
}
}
}
}
The code works and everything, but after doing the ask() function, just when the program loops back to main(), it prints "Input the action (add, remove, import, export, ask, exit):" twice instead of once. A friend of mine told me it could be an empty input left in cache that triggers this, so that it goes once through main() without actually taking user input.
Please, if anyone has experience with this I would really appreciate it to hear and learn about it and how to prevent it, cause it hinders me from finishing the project. Would changing the way how I take in users input help?

Return from `buildSequence` in Kotlin

I'm using the buildSequence function in Kotlin. How do I end the iteration in the middle of the function? I'm looking for something similar to C#'s yield break statement.
My code looks something like the following. I'm stuck at the TODO.
fun foo(list:List<Number>): Sequence<Number> = buildSequence {
if (someCondition) {
// TODO: Bail out early with an empty sequence
// return doesn't seem to work....
}
list.forEach {
yield(someProcessing(it))
}
}
EDIT
Apparently, I misdiagnosed the source. The issue is not returning from the buildSequence function. The following works for me:
fun foo(list:List<Number>): Sequence<Number> = buildSequence {
return#buildSequence
list.forEach {
yield(someProcessing(it))
}
}
EDIT 2
The issue is that I put the return in a local helper function that validates data at multiple points in the buildSequence (Hence the helper function). Apparently I'm not able to return from buildSequence within the helper function. The error message was not terribly helpful...
Just use return#buildSequence, which is a labeled return from lambda, while an unlabeled return would mean 'return from the function foo'.
See also: Whats does “return#” mean?
Since Kotlin v 1.3.x preferred sequence syntax changed. (buildSequence is replaced by kotlin.sequences.sequence)
Updated "early return from generator" code snippet (includes try-catch and == null early return examples) for post 1.3.x Kotlin:
// gen# is just a subjective name i gave to the code block.
// could be `anything#` you want
// Use of named returns prevents "'return' is not allowed here" errors.
private fun getItems() = sequence<Item> gen# {
val cursor: Cursor?
try {
cursor = contentResolver.query(uri,*args)
} catch (e: SecurityException) {
Log.w(APP_NAME, "Permission is not granted.")
return#gen
}
if (cursor == null) {
Log.w(APP_NAME, "Query returned nothing.")
return#gen
}
// `.use` auto-closes Closeable. recommend.
// https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/use.html
cursor.use {
// iterate over cursor to step through the yielded records
while (cursor.moveToNext()) {
yield(Item.Factory.fromCursor(cursor))
}
}
}
(Thx for all the prior posts that helped me get on "named return" track.)

How to tell IDEA/Studio that the null check has been done?

I'm developing with Android Studio/IntelliJ IDEA.
I have enabled the inspection check called "Constant conditions & exceptions" that shows a warning if I am risking a NPE, such as:
String foo = foo.bar(); // Foo#bar() is #nullable
if (foo.contains("bar")) { // I'm living dangerously
...
}
I have the following in my code:
String encoding = contentEncoding == null ? null : contentEncoding.getValue();
if (!TextUtils.isEmpty(encoding) && encoding.equalsIgnoreCase("gzip")) {
inputStream = new GZIPInputStream(entity.getContent());
} else {
inputStream = entity.getContent();
}
Here's the source code of TextUtils#isEmpty(String):
/**
* Returns true if the string is null or 0-length.
* #param str the string to be examined
* #return true if str is null or zero length
*/
public static boolean isEmpty(CharSequence str) {
if (str == null || str.length() == 0)
return true;
else
return false;
}
I'm not risking any NPE because TextUtils#isEmpty(String) would return true to a null pointer.
However I'm still getting the little Method invocation 'encoding.equalsIgnoreCase("gzip")' may produce 'java.lang.NullPointerException' warning, which can be annoying.
Is it possible to make this check smarter and ignore the NPE warning if there's already a null-check done?
You can look into the link that Peter Gromov mention in his answer.
Created some simple classes that resemble your setup:
A class with a method annotated with #Nullable:
The TextUtil class with it's isEmpty method:
And finally the main class calling the TextUtil#isEmpty:
Now if you enter the File -> Settings... and go to Inspections ->Constant conditions & exceptions part you can change the Configure Assert/Check Methods to cater for your isEmpty method:
Add a new IsNull check method:
Enter the TextUtil class, isEmpty method and CharSequence parameter:
This gives this Assert/Check Method Configuration window:
Press Ok and then Ok again to go back to the editor view and you'll see that the inspection disappeared:
You are actually telling IntelliJ that the isEmpty method is doing a null check on the str parameter.
You could use //noinspection ConstantConditions that will remove the NPE warning for the following line, like this:
String encoding = contentEncoding == null ? null : contentEncoding.getValue();
//noinspection ConstantConditions
if (!TextUtils.isEmpty(encoding) && encoding.equalsIgnoreCase("gzip")) {
inputStream = new GZIPInputStream(entity.getContent());
} else {
inputStream = entity.getContent();
}
You can use #SuppressWarnings("ConstantConditions") annotation.
#SuppressWarnings("ConstantConditions")
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int indexViewType) {
if (inflater == null) {
inflater = LayoutInflater.from(parent.getContext());
}
ItemViewProvider provider = getProviderByIndex(indexViewType);
provider.adapter = MultiTypeAdapter.this;
return provider.onCreateViewHolder(inflater, parent);
}
Select "TextUtils.isEmpty".
Right Click -> Show Context Actions -> Add Method Contract.
Enter "null -> true".
Save the configuration xml.
Please check the details here
See http://www.jetbrains.com/idea/webhelp/configuring-check-assert-methods.html for IDEA 12.
In IDEA 13 EAP, you can add method contract: http://youtrack.jetbrains.com/issue/IDEA-93372
Unfortunately marked as "right answer" solution is of date. But I found equivalent for me solution.
The new versions of IDE work correctly with static methods. So the example from the question won't throw warning anymore.
TextUtils#isEmpty(String);
public static boolean isEmpty(CharSequence str) {
// your checks
}

Activating find/replace for jface TextViewer eclipse worbench action

I have made an eclipse plugin with TextViewer interface for displaying a text document but the standard find/replace stay in gray mode.
I assume you are using the TextViewer in a view rather than an editor. In this case:
Your view in which the TextViewer is used must "adapt" to org.eclipse.jface.text.IFindReplaceTarget i.e. its getAdapter() must return the target from viewer.
You need to explicitly register a handler for "org.eclipse.ui.edit.findReplace" command (which can be org.eclipse.ui.texteditorFindReplaceAction). Check out Platform Command Framework to get started.
I've used Martii Käärik's pointers for finding the answer to this question. I've got it working with the following code, which however uses an internal string identifier from TextEditor. Still, here it goes.
getAdapter() in the view must be implemented like this (viewer is an instance of TextViewer)
public Object getAdapter(Class adapter) {
if (IFindReplaceTarget.class.equals(adapter)) {
if (viewer != null) {
return viewer.getFindReplaceTarget();
}
}
return super.getAdapter(adapter);
}
In createPartControl() of your view, add this code:
FindReplaceAction findAction= new FindReplaceAction(ResourceBundle.getBundle("org.eclipse.ui.texteditor.ConstructedTextEditorMessages"), null, this);
IHandlerService handlerService= (IHandlerService) getSite().getService(IHandlerService.class);
IHandler handler= new AbstractHandler() {
public Object execute(ExecutionEvent event) throws ExecutionException {
if (viewer != null && viewer.getDocument() != null)
findAction.run();
return null;
}
};
handlerService.activateHandler("org.eclipse.ui.edit.findReplace", handler);
No XML required.