Using Java 9 Modularization to Ship Zero-Dependency Native Apps

(steveperkins.com)

227 points | by StevePerkins 2377 days ago

15 comments

  • phreack 2376 days ago
    While Electron's popularity was a boon to the desktop app scene, I keep on dreaming that JavaFX applications made with Kotlin, jlink, Gluon's scene builder (or maybe even something better) will gain enough popularity to attract a healthy open source community for cross platform desktop apps.

    It feels like the tools are almost where they need to be and finally coming together!

    • adamhepner 2375 days ago
      OK, so question time: I haven't done any Java (let alone Kotlin) coding now for what seems like ages, but will need to implement a relatively simple, yet cross-platform client for my upcoming application. It will probably sound extremely silly, but were I to write a GUI that speaks to a REST API, where should I start doing my research?
      • phreack 2375 days ago
        If you have more recent experience on C++, Python or Javascript then you should be looking into Qt, PyQt, Electron (respectively) or other alternatives first, but if you're willing to try the Java environment you could look into the following components to get you started:

        -Kotlin to speed up development

        -Gradle as a dependency manager

        -Retrofit + OkHTTP to create a type safe backend API definition

        -JavaFX for the GUI components

        -Gluon's scene builder if you like creating your FX views in xml, with a visual editor

        -RX as a powerful library for async tasks

        -Gson or Jackson as a JSON parsing library

        -IntelliJ if you like coding with IDEs, for its massive refactoring capabilities

        It's a lot to take in if you're unfamiliar, but together they all come to form really solid desktop applications.

  • capelio 2376 days ago
    Even so, Java is now at a place where you can ship self-contained, zero-dependency applications that are comparable in size to other compiled languages (and superior to web-hybrid options like Electron).

    For cross-platform desktop GUI apps, I would argue that JavaFX combined with Java 9 modularization is hands-down the best choice available today.

    Electron is succeeding in the desktop GUI space because it tears down the barriers to desktop app development. While the author's article is excellent, when it comes to Electron, he (like most engineers) is still missing the point: the choice between Electron and its alternatives doesn't pivot on file size.

    • ssijak 2376 days ago
      Well, will see how Electron will pan out in the end. While I dislike default Java Swing GUI (it can be made easily to look native but many devs previously did not do it), JavaFX can be made to look like anything with almost weblike feel to development and animations. Now, more than the looks I dislike the slowness and utterly unacceptable memory Electron apps consume. I ditched Electron and VSCode (it is a little better than Atom) because I don`t want to have my text editor eat 500mb ram to open 1 medium file and crash on large ones. Same for Slack and other Electron apps. And it is not even funny to see dev console when some Atom plugin or whatever crash. I`m interested how many devs also ditched this two editors ONLY because of Electron bloat.
      • jrs95 2376 days ago
        I'm using JetBrains IDEs now instead. They're definitely not lightweight, but it's built in functionality is generally a lot more stable than what I get with text editors + a lot of plugins.
      • pjmlp 2376 days ago
        Electron pop culture made me buy Sublime Text.
        • ssijak 2376 days ago
          For me it finally pushed me enough to switch to Vim for web dev work. But I do have Sublime for just in case.
        • jjoonathan 2376 days ago
          What a breath of fresh air Sublime is.
      • threatofrain 2376 days ago
        There are probably more people hopping onto VS Code than people jumping off.
      • cyberpunk0 2376 days ago
        Probably not many. They are too busy developing instead of over obsessing over small performance gains
        • shakna 2376 days ago
          My cursor lagging is not a small concern. It disrupts the flow between code being re/written and the mental model I'm trying to pour out.

          Text input lag is an issue every editor has to deal with, and many go to extreme lengths to optimise it. Electron makes it far more difficult than most editors to fix, and every lag issue opened on VS Code seems to get decent attention, (and patches), and comparisons to Sublime Text.

          Seems to be something I'm not alone in caring about.

        • jrs95 2376 days ago
          It's not a small gain for me, it's basically a necessity for keeping RAM low enough. I have 16GB on my work machine, and that's barely enough.
          • KGIII 2376 days ago
            Your comment ties in so very well with an above exchange concerning resultant binary sizes. RAM was once $100 for a MB, I paid $400 for 4MB of RAM.

            Shocking, when I look back at it.

    • aaomidi 2376 days ago
      Yes, but it's electron.

      I've honestly seen only one properly written Electron app and it's VSCode. Everything else electron sucks. VSCode is not great either but it's much better than say, Atom or Slack.

      • bpicolo 2376 days ago
        Discord is great
        • Spivak 2376 days ago
          Sure, but Discord's web app and their native app are basically equivalent. The native app gives a little more system integration (like global hotkeys and direct access to sound hardware) but fundamentally the Discord app is just a webview.

          I don't think anyone doubts that a high-quality website wrapped in a webview won't be at least the same quality. The question is whether "web-native" platforms can do more than just be a branded browser.

        • supergreg 2376 days ago
          So is gitkraken.

          But I assume these apps have spent a considerable amount of time in optimizing electron, which not everyone can do.

          • erikbye 2376 days ago
            While some may find GitKraken visually pleasing, it can't be used for big repos; didn't even manage to open a few of the ones I tried.
            • crispinb 2376 days ago
              I was curious as I've never found a standalone visual git client I liked as much as IntelliJ's integrated one. So I downloaded it, found it was 1/4 of a GB and wouldn't look at a local repo without logging in to a web service. Deleted.
              • SOLAR_FIELDS 2375 days ago
                I still haven't found anything better than IntelliJ's triple column view for resolving merge conflicts. Is there anything similar in a more lightweight editor?
              • friendzis 2376 days ago
                Some years ago I was evaluating GUI git clients (the landscape has changed since) for rather simple flows and found SmartGitHg simple enough to setup and explain in under an hour and powerful enough not to drop to a shell. No affiliation here.
              • philliphaydon 2376 days ago
                It never used to require logging in but the moment they added that I deleted it.
      • richardwhiuk 2376 days ago
        Slack?
        • blueline 2376 days ago
          stutters horrendously very often for my work setup (~800 people). also eats tons and tons of memory and kills my battery
          • cyberpunk0 2376 days ago
            Anecdotal problems
            • KGIII 2376 days ago
              Another anecdote; your comment is the only one I've ever noticed that appears to be defending Slack. From an outsider looking in, I'm not sure why it is so popular.
              • always_good 2375 days ago
                It's popular because technical superiority isn't why people use software.

                For example, Spotify eats 100% CPU if I leave it open for 24 hours yet I don't think I've met someone in the last year that doesn't have Spotify running on their computer.

                • KGIII 2375 days ago
                  If it helps, I don't have Spotify.
        • NikolaeVarius 2376 days ago
          Slack takes up 1.3 gb of RAM if I don't restart it at least once a week
    • Avshalom 2376 days ago
      >tears down the barriers to desktop app development

      Yes, then it replaces them with the barriers to web app development.

      • Spivak 2376 days ago
        Sure, but more companies have the story of needing a web app anyway which requires a specific tech stack. So you can either maintain two tech stacks or you can port your webapp to native.

        Having a beautiful, easy to develop, and easy to maintain native stack means nothing when you don't have an answer to, "How do we then reuse our code in a browser?".

        • pjmlp 2376 days ago
          You don't.

          Use the browser for what it was meant for, hyperactive documents.

          Everything that matters is on the backend accessed via Web APIs.

    • _sh 2376 days ago
      Electron sits in the same hybrid space as Cordova/Phonegap, and will suffer the same fate once React Native, or something similar, starts eating its lunch.
      • Can_Not 2375 days ago
        There are some ReactNative alternatives calling themselves "native" that are only "native looking css in a webview". The future will probably only get more ambiguous.
    • profalseidol 2376 days ago
      I can be, for very small very cheap devices.
    • gdfhhgddhjj 2376 days ago
      It’s really not clear what the electron app even provides over the same app in chrome. Its own icon, sure, but the behavior is just as bad as on the web—just take slack for example.
      • cyberpunk0 2376 days ago
        It offers access to file system and system resources as well as multi platform build support. Developers like all people will whine over anything. For students and indie devs who have little time, support, and resources things like electron are great
        • gdfhhgddhjj 2376 days ago
          Right, but does eg slack actually use any of that? It’s not a great native client by any stretch—it doesn’t use a native UI, it’s not particularly snappy, and it doesn’t do any special integration. So, it seems that electron is mostly a way to distinguish certain sites from others, not that they provide a better experience.

          Granted I do like the distinct app icon. But electron should mean more than that to qualify as meaningfully native.

          • alexasmyths 2375 days ago
            What electron gives Slack is A) local install and B) proper notifications.

            So Slack gets an icon on the homescreen and possibly offline notification + notification integration with the OS.

            That might be pretty limited from a technical perspective, but it's a massive product thing from a product perspective.

            Also, it's possible they may use file access for caching/storage etc..

      • 0xFFC 2376 days ago
        Not closing and losing your data when your chrome crashes?
  • tootie 2376 days ago
    While everyone is excited about how this helps desktop app development, this is also going to simplify server deploys. If you've got a full java stack, you won't need to do anything to provision a server.
    • tuananh 2376 days ago
      i think this is a better selling point.
  • firdak 2376 days ago
    So, after "optimizations [...] to further reduce the resulting bundle size", a Java command-line "Hello World" is still 21.7 MB. I've found a Node.js version (using node-packer [1]) to be about the same size.

    However, as mentioned in the article, "Hello World" in Go is an order of magnitude smaller. The article may be right that Java is "the best choice available" for cross-platform GUI apps, but for cross-platform command-line tools, I think Go is currently the best option. IMO Go provides the best tradeoff between ease of development, ease of distribution and runtime performance.

    [1] https://github.com/pmq20/node-packer

    • zserge 2376 days ago
      Since Go and Electron are mentioned, let me offer a web UI library for Go: https://github.com/zserge/webview (I know UI has been a problem for Go apps for a while and is often a stopper when it comes to writing desktop apps in Go).

      The library creates a full-screen webview window and lets you write UI code in HTML5/CSS/JS connecting it to the core app logic written Go. It provides JS-to-Go bindings allowing to call Go code from JS and vice versa.

      The whole library is a single header file of ~800LOC with a thin Go wrapper. It supports Windows 7+, MacOS, Linux and OpenBSD.

      Executables are 5-10MB in size and take about the same amount of RAM. No external libraries are used on Windows and MacOS, on Linux gtk-webkit is required, but it is typically one "apt-get" command to run.

      • mmargerum 2375 days ago
        This looks pretty cool. I noticed on windows this uses mshtml. What browser tech does this use on windows 10?

        Another question is around intercepting xls/doc responses to load them into office. Is there a way to do this with this framework?

        Thanks!

        • zserge 2375 days ago
          On Windows 7 SP1 it uses IE11. Same on Windows 10. On some Windows 8 it might use IE10, which is still not that bad.

          Sorry, can't tell much about xls/doc. It's aimed to be a web UI for your app. Normally, you app would be a web server then. So if you want to handle certain requests and open external apps - you surely can do it.

    • flavio81 2375 days ago
      People need to stop comparing app sizes of "Hello World" apps and use a more real, more complete application as an example. One that does most of the things that one would do in the platform, for starters.

      If we "compare by Hello World" then Assembly/handwritten bytecode would win, but what's the point?

    • nerdponx 2376 days ago
      2.17 MB is still enormous for a "hello world" binary.
      • c_shu 2376 days ago
        No. 2.17 MB is NOT enormous. Usually there is no runtime library. In contrast, C or C++ runtime libraries can easily exceed that size. For example, vc_redist.x64.exe is 13.9 MB.
        • unscaled 2376 days ago
          It's a matter of platform and the libraries that you're using.

          After all, back in the days we had 360k floppy disks, and executable written in C which did much more than just printing out "Hello world" would fit comfortably into less than half of that.

          Modern C and C++ runtimes are bloated, because a 2MB executable isn't considered huge anymore and dynamic linking is common.

          But you can have a 5k static executable printing "hello world" on Linux if you just trade in your stdlibc to musl. People have also managed to use musl with Rust to produce pretty small executables: https://lifthrasiir.github.io/rustlog/why-is-a-rust-executab...

        • joosters 2376 days ago
          (Note: The size in the article is 21.7 MB, and not 2.17 MB!)

          I just tried building a statically linked 'hello world' c++ program, and co-incidentally, the binary also happened to be 2.1 MB!

             #include <iostream>
             
             int main( int, const char *[] )
             {
                std::cout << "Hello World!" << std::endl;
                return 0;
             }
          
          
          'g++ -static -o hello hello.cpp' produces a binary of 2191112 bytes (Linux x64). Stripping it of debug symbols leaves a 1.7 MB file.
      • camus2 2376 days ago
        Go runtime is included in the executable. C or C++ do not automatically do that when writing a simple "hello world" and compiling it into an executable. stdio isn't statically linked by default.

        And when rid of debugging symbols, even when importing the fmt package :

            package main
        
            import "fmt"
        
            func main() {
                fmt.Print("Hello World")
            }
        
        go build -ldflags "-s -w" hello.go

        is 1.3MB .

    • friendzis 2376 days ago
      Java and Node need to ship their own virtual machine while native code does not (others mentioned that runtime may be dynamically linked). VM startup time is ludicrously high compared to execution time of "userspace" code in CLI tool, making such rintimes no-go for CLI tools (except for web devs, apparently).
  • generichuman 2376 days ago
    I want to use JavaFX to develop cross-platform apps but I feel JVM uses too much memory even for little things.

    It's been a while since I've used Java to program, has the memory situation changed? or are there any other solutions for lowering the JVM memory usage?

    • slackingoff2017 2376 days ago
      Java will use as much memory as you give it. Higher heap size is better for performance up to around 32GB. For most Java apps you can limit heap to 256M or less with little consequence.

      AFAIK Java uses less ram than Python and JavaScript, only common languages that beat it are Golang and C/C++

    • pjmlp 2376 days ago
      Apparently lack of memory isn't something that affects Electron popularity.

      Java applications use much less memory, unless their coders weren't paying attention during algorithms and datastructures lectures.

    • vbezhenar 2376 days ago
      I used Swing Java applications on a computer with 512 MB RAM. Sure, Java eats more than C++, but it should be pretty in line with JavaScript which is a very popular choice nowadays.
    • jm547ster 2376 days ago
      Default heap size is over-generous in most JVM implementations, experimenting with smaller settings is the solution.
  • 0xFFC 2376 days ago
    Great article. Pair this with AOT. Then you have unbeatable combination. Productivity of java with availability of Native features. Count me in!
  • jrs95 2376 days ago
    This looks pretty awesome. I haven't used JavaFX before, but if it's easy enough to deliver high quality UX with it, I'll be using this for any side project desktop apps I end up working on.
  • bmn__ 2375 days ago
    TFA reads like GCJ does not exist, a classic lie by omission. Don't become a victim of misinformation!

    Compiling to small, native binaries (i.e. JRE not needed) is possible since at least 10 years ago. Let's examine this application as an example: http://sancho-gui.sf.net

        /tmp/sancho-0.9.4-59-linux-gtk$ ls -hs ./sancho
        13M ./sancho
    
        /tmp/sancho-0.9.4-59-linux-gtk$ du -hs ./lib
        740K ./lib
    
        /tmp/sancho-0.9.4-59-linux-gtk$ ldd ./sancho
        linux-gate.so.1 (0xf7f71000)
        libm.so.6 => /lib/libm.so.6 (0xf7e30000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xf7e11000)
        librt.so.1 => /lib/librt.so.1 (0xf7e07000)
        libdl.so.2 => /lib/libdl.so.2 (0xf7e02000)
        libc.so.6 => /lib/libc.so.6 (0xf7c29000)
        /lib/ld-linux.so.2 (0xf7f73000)
    • kryptiskt 2375 days ago
      GCJ is dead, there is no development and it has been removed from GCC.
  • zengid 2376 days ago
    I'm unfamiliar with the state of the art, but could this make it possible to target iOS with a bundled JVM?
    • pjmlp 2376 days ago
      It is possible using an AOT compiler for Java, like Codename One or Robot VM.

      So far Oracle has shown little interest into integrating such features into OpenJDK, but the ongoing efforts to add AOT compilation to it, might become a possible solution.

    • filereaper 2376 days ago
      iOS tends to favour direct native code, hence the use of Objective C and Swift for iOS development.

      Given the already large ecosystem built on these lanuages, its unlikely they'll pivot to a JVM based system.

      • pjmlp 2376 days ago
        There are AOT native Java compilers for iOS, the majority just tends to ignore them.
    • ssijak 2376 days ago
      No.
      • MBCook 2376 days ago
        ssijak is right, Apple still doesn’t allow general purpose interpreters, so you can’t put an app in the store built on the JVM.

        As others have pointed out you could compile the Java code to native code before submitting the app, the way C# apps are put in the store.

  • ksec 2376 days ago
    15 years since I last looked at Java for Desktop Apps and shipping as binary. I remember there were also GCJ as the commercial JET alternative.

    Graal and Truffle are progressing along. I wonder what happen to SubstrateVM, which allows AOT of Java. I assume with SVM the binary size can be further reduced and much faster startup time.

  • mmargerum 2375 days ago
    Boy if I could pair this with Clojure I’d seriously consider building desktop apps again.
  • i386 2376 days ago
    Oracle have broken and delayed releases of Java so some people can get slimmer binaries? Hardly seems like a good trade off when storage is the cheapest it’s ever been.
    • blinkingled 2376 days ago
      It's not about storage. Most desktops don't have a JRE installed and downloading the full non-modular JRE and installing it before being able to run the program is a hassle compared to providing a stripped down, self sufficient, linked version of the app that's one third in size.
      • i386 2376 days ago
        Who cares about desktop apps? Most Java development is done on the server where the size of your runtime isn't a constraint. Breaking reflection, delaying language features, releases, etc is a very poor tradeoff for the module system that has been delivered.
        • blinkingled 2376 days ago
          Well, now you can care about Java desktop apps - that's kind of the point of all this :)

          And server apps don't really switch that fast to newest Java release. Only now we're seeing JDK7 based things for example.

      • erik_seaberg 2376 days ago
        End result: install nine apps, end up with three variously outdated copies of the JRE, none of which benefit the tenth app I install.

        It's frustrating how we're wallowing in problems that had already been solved for most of my career.

        • blinkingled 2376 days ago
          With JNLP you could presumably keep all those JREs updated automatically - no issues other than storage which isn't.
  • tpolzer 2376 days ago
    Does it have cross platform Hi-DPI support? No.
    • pjmlp 2376 days ago
      Yes it does, when using Java 9.
    • ZenoArrow 2376 days ago
      Are you joking? I can't tell.

      Just in case you aren't, what do you think is required for a platform to support Hi-DPI displays?

      • Pyxl101 2376 days ago
        I'm not the OP, but I assume hi-DPI support means that applications scale up their GUI sizes appropriately based on the DPI.

        When I use a hi-DPI display (like 4K displays), a lot of old software renders text and widgets too small to see, because they were programmed to display things as so-many pixels high, without concern for DPI. It's frequently a problem with old video games, though it affects regular applications too.

        • Sophistifunk 2376 days ago
          It's more than that, simply pixel-doubling the UI is also terrible. Real hi-DPI support (to me) is actually rendering at hi-dpi.
          • ZenoArrow 2375 days ago
            What difference does it make if the standard resolution is Hi-DPI or not? Can you visually tell the difference between pixel doubling and other methods of designing for Hi-DPI?
      • harrygeez 2375 days ago
        For what's it's worth, I've written Java 8 on macOS and it 'just works'. I didn't have to do anything to make it look good in hidpi.
        • tpolzer 2375 days ago
          Yes, it works on Mac, but not on Linux...
  • camus2 2376 days ago
    > A “Hello World” CLI written in Go compiles to around 2 MB.

    Nitpick but hello-world in Go :

        package main
       
        func main(){
            print("Hello World")
        }
    
    
    is < 1MB on most computers (900KB on windows). No need to import the "fmt" package.
    • pjmlp 2376 days ago
      Except that isn't actually portable Go code, because you are using an unsupported function that can be removed at any time.

      "The print built-in function formats its arguments in an implementation-specific way and writes the result to standard error. Print is useful for bootstrapping and debugging; it is not guaranteed to stay in the language."

      https://golang.org/pkg/builtin/

    • brobinson 2376 days ago
      Don't forget to pass -ldflags "-s -w" to `go build`.

      Debugging symbols are over 50% of most Go binaries I see, and you don't even need them to get stack traces from panics.

      Combined with `upx --ultra-brute`, you can get static Go binaries down to about 12-15% of their plain `go build` size in my experience. (This also assumes CGO_ENABLED=0)

    • morecoffee 2376 days ago
      print() is a nonstandard function and will be removed eventually.
    • slackingoff2017 2376 days ago
      You can get under 200KB in Java easily by using proguard or similar to strip unused code from your dependencies.
      • pebers 2376 days ago
        But that 200KB isn't a standalone executable. The Go example would be a lot smaller if it just distributed some unlinked object code with no runtime.
        • slackingoff2017 2376 days ago
          True. The JVM is big. I've been meaning to try Golang one of these days, I see it as Java's spiritual successor
          • eropple 2376 days ago
            I tend to view it more as a regressor. Golang is a conservative retrenchment towards Java pre-1.5 in a lot of ways. (And that may be fine for some use cases; I get the appeal even if I think it's misguided.)
            • holydude 2376 days ago
              Ok you have Nim,Crystal and / or Rust if you insist. There is actually a reason why Go is gaining momentum.
              • eropple 2375 days ago
                Sure, there certainly is: it looks easy at first blush and scales moderately well. And that's fine, if you understand its drawbacks, and what Go aficionados try hard not to address is that Golang has a severe complexity wall. It is a large reason, along with faddish trendiness, why the Go universe clings so heavily to microservices: because the Golang is structured lends itself to writing messy code that is more easily combated by splitting into different systems rather than just writing modular code that respects encapsulation (in part because its type system is lousy, in part because error handling with deeply nested trees is harder than it needs to be, etc.). That this also creates additional problems--request tracing is an ongoing tire fire--is often elided a little bit, too.

                In my experience, Go exhibits human-scaling problems long before even dynamically typed languages and significantly before Java, Kotlin, or the like. And the arguments to deployment are defanged both by Docker and by that it's usually not the developer who picks it who ends up building the CM around it in the first place (that's why they hire people like me, and why I have had to become uncomfortably familiar with Golang, its ecosystem, and the habits of your average Golang developer: because the person running the systems it runs on is inevitably the backstop for when those programs spit the bit).

                But in the five-minute-demo-to-make-production-decisions universe, it plays really well.

          • pjmlp 2376 days ago
            Not really, unless you enjoy to program in Java 1.0 again.
          • Cyph0n 2376 days ago
            I actually see Scala as Java's spiritual successor. Go is in an entirely different ballpark.
      • camus2 2376 days ago
        Sure, but I didn't apply any specific code optimization or third party tool here.
        • slackingoff2017 2376 days ago
          Progaurd is default on Android and some other environments, it's not anything exotic.
    • virmundi 2376 days ago
      Hey! You win the worthless example competition! See the front desk for your prize. How about comparing a full stack, monolith app in Java vs Golang? While you’re at it, don’t just compare binaries. Compare how well it handles concurrency. Compare how well it handles templates. Or how smoothly it handles DB interaction. Then look at all this and compare the population of Golang vs Java devs. Compare how well you can leverage existing language knowledge while working on a major mobile platform too like Android.

      Binary size for a hello world app means little to nothing. I can beat that with Bash: echo “hello, world!” Compare to real applications.

      • dang 2376 days ago
        This comment breaks the site guidelines. Please don't do flamewar things on HN, even if someone else's comment seems unfair.

        https://news.ycombinator.com/newsguidelines.html

      • camus2 2376 days ago
        Your message is stupid and aggressive. The author of the blog post himself compares hello-world executable sizes, so what are you complaining about?
        • dang 2376 days ago
          Would you please not reply to a bad HN comment by making the thread even worse? The site guidelines explicitly ask you not to do this.

          Your account unfortunately stands out in my mind as one which has posted many nasty comments to HN over the years (as well as many good ones), so glass houses and all that. If you would read https://news.ycombinator.com/newsguidelines.html and post only scrupulously respectful comments from now on, we'd appreciate it.

      • camus2 2376 days ago
        > Binary size for a hello world app means little to nothing.

        I'm just quoting the original article. If you want to get mad at someone be mad at the OP. The whole point of the post is executable sizes.

  • 0xbear 2376 days ago
    “Zero dependency” after you install a 80MB JRE. You keep using this word. I don’t think it means what you think it does. Statically linked C is zero dependency. Go is zero dependency. Copy a binary to the target system and it runs. There’s nothing else to install.
    • kbenson 2376 days ago
      It gets a little fuzzy. Go and C are only zero dependency once you have their platforms installed (the OS). The JRE is only a little on top of that, ships with some systems out of the box, and is generally ubiquitous enough that you can probably rely on it being present it over a particular OS being present.

      Ita not really zero cost, but neither is an app that only has binaries for an OS you don't run.

    • wstrange 2376 days ago
      The bundle includes the JRE.