For the middle articles of this series, we’ve been focusing on a single method, and demonstrating how to improve this method, one smell at a time. While it has been… useful… that a single method has demonstrated so many smells, if you came across that method in real life it wouldn’t be obvious what to do with it.
IntelliJ IDEA 2017.3 now prompts you to choose database/schema along with a datasource when you try to run an SQL file from the Project tool window:
Jumping to console from datasource
For easier navigation, the context menu on a datasource in the Database tool window was upgraded. Choose Jump to Console and you’ll now have a handy menu which allows you to quickly switch between your consoles.
Right-side alignment for numeric data
For better readability, the IDE aligns the data in the table editor for numerical columns with the right side:
XQuery and XPath coding assistance for Microsoft SQL Server
Last but not least, the XQuery/XPath support for Microsoft SQL Server is now provided through the Injected Languages feature:
Place the caret to a needed code fragment and press Alt+Enter. Then choose Inject language or reference, and select XQuery or XPath:
Since the feature has been asked for by some of our users, we backported it to IntelliJ IDEA 2017.2 as well.
To give these new features a try, download the EAP build. And as usual, bug reports along with your feedback, are very welcome in our issue tracker.
Last week we announced the opening of the EAP for IntelliJ IDEA 2017.3, the upcoming IDE update which will be released this fall. In the announcement we briefly mentioned some of the major changes the update will deliver. Let’s talk about them in a bit more detail.
The article in this series that has so far provoked the most responses was on iteration. Today, I’m talking about if statements (conditionals). I’m not intending to go after any sacred cows or anything – for loops and if statements are pretty much the first things we learn in many programming languages. They’re a fundamental part of languages like Java. But just because these basic building blocks exist doesn’t mean they should be our goto strategy (see what I did there?) every time. We could program in assembler but we don’t. We could use a hammer for every job around the house, but we don’t (well…).
If statements are very useful, and often the right tool for the job, but they can also be a smell. Remember that by “smell” I mean “code that you should look carefully at to see if there’s a simpler/easier to understand, approach”. I don’t mean “if statements are evil never use them”.
In the last article I introduced a large and complex method, validateQuery. The focus of that article was how to simplify the method looking only at the “smell” of mutability, but there’s actually one very simple change that can chop the method nearly in half.
The major news in August was for Android, with the release of Oreo. Other than that, the rest of the Java world seems to be holding its breath waiting for Java 9, due (finally!) this month. The lull in pure technology news gives us a chance to explore other topics that affect us as developers and members of a larger organisation, so this month we have a whole section on Culture.
In the article about deeply nested code I wanted to change getMappedField to return an Optional value. The change to the method was fairly trivial, the change to the code that calls that method… well, that turned out to be another matter altogether.
The Run/Debug tool windows for Spring Boot applications now contain an Endpoints tab which will include information retrieved from the application’s actuator endpoints Beans, Health, and Mapping. ‘spring-boot-starter-actuator’ must be added as a dependency to the application to enable these endpoints. The Spring Boot Run/Debug configuration option ‘Enable JMX agent’ must be also enabled in order to make new Endpoints tab appear.
For Gradle-based projects: issues with automatic setup for have been fixed, and a run configuration can now be created automatically as well (see Application Settings below).
Support for custom configuration files is now available. To define a custom spring.config.name, select the Spring Boot fileset under Facets (in the Project Structure) and open the customization dialog via toolbar button:
You can also add (additional) configuration files via “+” button. Any bootstrap.* files that are found are always added automatically.
Completion for configuration keys has been improved: keys referring to types not on the classpath (e.g. database specific keys) are shown at the bottom of the completion list,, “local” keys defined in additional-config.json are at the top.
In Spring Boot 1.5, an additional “level” (warning/error) for denoting deprecation status of configuration keys was added. This is now fully supported in IntelliJ IDEA and highlighted accordingly in configuration files and documentation.
Detected auto-configuration classes are now sorted according to @AutoConfigureOrder and @AutoConfigureAfter|Before. For @ConditionalOnProperty the actual configuration key values will now be evaluated so IntelliJ IDEA will be able to more correctly evaluate autoconfigured Spring Beans in the code.
If you have a custom banner file that doesn’t have the standard banner.txt name and your configuration includes the banner.location setting, it is fully recognised and will offer code highlighting and completion.
Finally, the Spring Boot application settings are easier to find. They’ve been grouped together under a new Spring Boot section in Languages and Frameworks. As mentioned earlier, now the “Create Run Configuration automatically” setting applies to Gradle as well as Maven.
Last time we looked at some suspicious nested code, and I suggested that the best way to deal with this was to move some of it into a different class to stop the original class having to understand the internals of how the data was stored.
The Smell: Iteration
But that’s not the end of the story. In this article I want to explore a different problem that code iteration might be pointing to. The nested iteration in the last example suggested the logic was in the wrong place. The existence of iteration at all in our new hasName method (whether implemented as a for loop or using the Streams API) suggests another problem: this might not be the correct data structure to store the names in.
This may even be hidden (or at least less obvious) when using the Streams API because this gives us a readable way to query our collection. But it doesn’t necessarily give us a fast way to query our collection.