Callbacks are hard to compose together, quickly leading to code that is difficult to read and maintain (known as “Callback Hell”).
Future objects are a bit better than callbacks, but they still do not do well at composition, despite the improvements brought in Java 8 by CompletableFuture. Orchestrating multiple Future objects together is doable but not easy. Also, Future has other problems:
It is easy to end up with another blocking situation with Future objects by calling the get() method.
They do not support lazy computation.
They lack support for multiple values and advanced error handling.