Interrupting Executor Tasks

There’s this usecase that is not quite rare, when you want to cancel a running executor tasks. For example, you have ongoing downloads that you want to stop, or you have ongoing file copying that you want to cancel. So you do: ExecutorService executor = Executors.newSingleThreadExecutor(); Future<?> future = executor.submit(new Runnable() { @Override public void run() { // Time-consuming or possibly blocking I/O } }); .... executor.shutdownNow(); // or future.cancel(); Unfortunately, that doesn’t work. Calling shutdownNow() or cencel() doesn’t stop the ongoing runnable. What these methods do is simply call .interrupt() on the respective thread(s). The problem is, your runnable doesn’t handle InterruptedException (and it can’t). It’s a pretty common problem described in multiple books and articles, but still it’s a bit counterintuitive. So what do you do? you need a way to stop the slow or blocking operation. If you have a long/endless loop, you can just add a condition whether Thread.currentThread().isInterrupted() and don’t continue if it is. However, generally, the blocking happens outside of your code, so you have to instruct the underlying code to stop. Usually this is by closing a stream or disconnecting a connection. But in order to do that, you need to do quite a few things. Extend Runnable Make the “cancellable” resources (e.g. the input stream) an instance field, which provide a cancel method to your extended runnable, where you get the “cancellable” resource and cancel it (e.g. call inputStream.close()) Implement a custom ThreadFactory that in turn creates custom Thread instances that override the interrupt() method and invoke the cancel() method on your extended Runnable Instantiate the executor with the custom thread...

Development Overhead

What does a developer spend his time on? Writing code, debugging, thinking and communicating with colleagues (that includes meetings). Anything that is beyond these activities is unnecessary overhead (some meetings are also unnecessary, but that’s a different topic). And yet, depending on our language and tools, we have to do a lot more to support the process of writing code. These activities include, but are not limited to: manually format your code – the code has to be beautifully aligned and formatted, but that’s an extra effort. using search and replace instead of refactoring – few languages and tools support good refactoring, and that’s priceless in a big project manually invoking compilation – compile on save gives you immediate feedback; the need to manually run a compiler is adding a whole unnecessary step to your coding process slow compilation – ontop of the previous issue, if your compiler is slow, it’s just a dead time (mandatory xkcd) slow time-to-deploy – if the time from writing the code code to running it is more than a few seconds, then you are wasting enormous amounts of time. E.g. if you need to manually make builds and copy files on a local server. clunky resource navigation – if you can’t go to a given source file in a couple of keystrokes infrastructure problems – you depend on a database, a message queue, possibly some external service. Installing and supporting these components on your development machine can be painful. Recently we spent one day trying to integrate 3 components, some of which had docker instances. And on neither Windows, nor Mac, Docker worked...

On Java Generics and Erasure

“Generics are erased during compilation” is common knowledge (well, type parameters and arguments are actually the ones erased). That happens due to “type erasure”. But it’s wrong that everything specified inside the symbols is erased, as many developers are assuming. See the code below: public class ClassTest { public static void main(String[] args) throws Exception { ParameterizedType type = (ParameterizedType) Bar.class.getGenericSuperclass(); System.out.println(type.getActualTypeArguments()[0]); ParameterizedType fieldType = (ParameterizedType) Foo.class.getField("children").getGenericType(); System.out.println(fieldType.getActualTypeArguments()[0]); ParameterizedType paramType = (ParameterizedType) Foo.class.getMethod("foo", List.class) .getGenericParameterTypes()[0]; System.out.println(paramType.getActualTypeArguments()[0]); System.out.println(Foo.class.getTypeParameters()[0] .getBounds()[0]); } class Foo<E extends CharSequence> { public List<Bar> children = new ArrayList<Bar>(); public List<StringBuilder> foo(List<String> foo) {return null; } public void bar(List<? extends String> param) {} } class Bar extends Foo<String> {} } Do you know what that prints? class java.lang.String class ClassTest$Bar class java.lang.String class java.lang.StringBuilder interface java.lang.CharSequence You see that every single type argument is preserved and is accessible via reflection at runtime. But then what is “type erasure”? Something must be erased? Yes. In fact, all of them are, except the structural ones – everything above is related to the structure of the classes, rather than the program flow. In other words, the metadata about the type arguments of a class and its field and methods is preserved to be accessed via reflection. The rest, however, is erased. For example, the following code: List<String> list = new ArrayList<>(); Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); } will actually be transformed to this (the bytecode of the two snippets is identical): List list = new ArrayList(); Iterator it = list.iterator(); while (it.hasNext()) { String s = (String) it.next(); } So, all type arguments you have...

The DSL Jungle

DSLs are a common thing in the programming world nowadays. Many frameworks and tools decide to build a DSL for their…specific things. Builds tools are the primary candidates, but testing frameworks, web frameworks and whatnot also decide to define a DSL. With these DSLs you define build steps, web routing rules, test acceptance criteria, etc. What is the most common thing about all these DSLs? Two things. First, they are predominantly about configuration. Some specific way of configuring something specific to the tool or framework. The second thing is that you copy-paste code. Everytime I’m confronted with some DSL that is meant to help with my programming task, I end up copy-pasting examples or existing code, and then modifying it. Even though I’ve been working with a DSL for 8 months (from time to time), I just don’t remember its syntax. And you may say “yeah, that’s because you use bad DSLs”. Well, then I haven’t seen a good one yet. I’m currently using sbt, spray routing, cucumber for scala, previously I’ve used groovy and grails DSLs, and a few others along the way. But is it bad that you copy-paste existing pieces of code? Not always. You can, of course, base your configuration on existing, working pieces. But there are three issues – duplicate code, autocomplete and exploration. You know copy-pasting is wrong and leads to duplication. Not only that, but you may forget to change or remove something in the pasted code. And if you want to add some property, it would be good to be able to auto-complete it, rather than mistyping or, or forgetting whether...

Validate Configuration on Startup

Do you remember that time when you spent a whole day trying to fix a problem, only to realize that you have mistyped a configuration setting? Yes. And it was not just one time. Avoiding that is not trivial, as not only you, but also the frameworks that you use should take care. But let me outline my suggestion. Always validate your configuration on startup of your application. This involves three things: First, check if your configuration values are correct. Test database connection URLs, file paths, numbers and periods of time. If a directory is missing, a database is unreachable, or you have specified a non-numeric value where a number or period of time is expected, you should know that immediately, rather the application has been used for a while. Second, make sure all required parameters are set. If a property is required, fail if it has not been set, and fail with a meaningful exception, rather than an empty NullPointerException (e.g. throw new IllegalArgumentException("database.url is required")) Third, check if only allowed values are set in the configuration file. If a configuration is not recognized, fail immediately and report it. This will save you from spending a whole day trying to find out why setting the “request.timeuot” property didn’t have effect. This is applicable to optional properties that have default values, and comes with the extra step of adding new properties to a predefined list of allowed properties, and possibly forgetting to do that leading to an exception, but that is unlikely to waste more than a minute. A simple implementation of the last suggestion would like like this:...