We developed the high-speed routing engine GraphHopper in Java and have never regretted it (think Google Maps not network routers :)). Although I'm unsure if I would have used it for a trading systems as every GC hiccup can be problematic and for our use case GC hiccups need only to be under 10ms.
But still the topic ("trading system" or in our case "routing engine") is already very complicated due to the involved algorithms and C++ likely makes it a bigger challenge also regarding attracting good developers.
The memory waste in Java is the biggest challenge that you have to solve. Usually you solve this via primitive arrays i.e. do not use List<Point> but int[] x and y and before this gets complicated wrap this in an iterator or other thin Object (flyweight pattern?). And today you can use advanced GCs like ZGC or Shenandoah that work well also for >100GB of RAM and you can heavily reduce hiccups. And you need to be aware of some smaller pitfalls e.g. foreach loop or Java streaming API might be slower than the raw loop. But you should never follow rules or trust a "guru" and only use your performance tests to guide development :)
And in non-performance critical sections (70% of the code?) you just do not care and can program "idiomatic Java". Also do not underestimate the crazy work that a modern JIT can do for you.
And now after years of work we are for several aspects better or same memory-wise and speed-wise compared to other open source C++ routing engines. And the interesting thing is that IMO this is because of the tooling and habits (like rigorous testing) which reduces bugs and debugging sessions and slowly shifts your focus from language problems to the actual domain problems. But of course all very subjective.
But still the topic ("trading system" or in our case "routing engine") is already very complicated due to the involved algorithms and C++ likely makes it a bigger challenge also regarding attracting good developers.
The memory waste in Java is the biggest challenge that you have to solve. Usually you solve this via primitive arrays i.e. do not use List<Point> but int[] x and y and before this gets complicated wrap this in an iterator or other thin Object (flyweight pattern?). And today you can use advanced GCs like ZGC or Shenandoah that work well also for >100GB of RAM and you can heavily reduce hiccups. And you need to be aware of some smaller pitfalls e.g. foreach loop or Java streaming API might be slower than the raw loop. But you should never follow rules or trust a "guru" and only use your performance tests to guide development :)
And in non-performance critical sections (70% of the code?) you just do not care and can program "idiomatic Java". Also do not underestimate the crazy work that a modern JIT can do for you.
And now after years of work we are for several aspects better or same memory-wise and speed-wise compared to other open source C++ routing engines. And the interesting thing is that IMO this is because of the tooling and habits (like rigorous testing) which reduces bugs and debugging sessions and slowly shifts your focus from language problems to the actual domain problems. But of course all very subjective.