Java Desktop Apps?

Hi, so I recently discovered the online MOOC.fi, the free java programming course, and have just started it. What struck me is the introduction said its a write once, run anywhere platform. And i’ve been following the first couple of topics just fine on my Linux laptop.

So how come it is never mentioned along with they likes of snaps and flatpaks and appimages etc? It seems to be something that works cross platform, are there fundamental issues with it that mean nobody makes desktop apps with java?

1 Like

Don’t you still have to install a JRE (Java Runtime Environment) for java apps to work? This used to be one of the drawbacks to coding in java – “You can use my app, if you have this other program running.” Generally, the idea is that when a program is “compiled” it runs stand alone without the need for the RE. Maybe things have changed as i have not stayed up to date in this area.

1 Like

I don’t know much about this free course you’ve mentioned. I hope you find it useful; I might look into it too.

I first used Java in the mid-late 90s when it was new and upcoming and have continued to use it as and when I code. The write-once-run-anywhere philosophy of Java did become a little muddied especially of late when Android and iOS gained popularity. One definite advantage for me though, is code I write on Linux will generally run without altering or recompiling on Windows (if I have to use Windows, which is rare).

The JRE (Java Runtime Environment) is needed to run compiled Java code, because Java targets a virtual machine for the compiled code to run on which is implemented in the JRE for a particular platform, with the JRE interfacing with native OS as needed.

Flatpaks, Snaps and AppImage run on the native Linux platform as far as I am aware, even if they’re in containers to some extent, so they’re a bit different in that respect. Just my thoughts :slight_smile:

1 Like

Developers choose different tools/stacks for different reasons. Java is great, but it never really delivered on the promise of “write once, run everywhere” (although many would argue with me on this). Some of the disadvantages of Java in regards to desktop apps:

  • It’s heavy (takes up lots of space, uses lots of memory).
  • You need the JVM (Java Vritual Machine) on the client.
  • Desktop theming - it doesn’t keep the operating system’s “native theming”.

Here’s a quick example using the Swing GUI framework:

import javax.swing.*;  

public class SwingExample {  
  public static void main(String[] args) {  
    JFrame frame = new JFrame();
    JButton button = new JButton("Hello there!");  
    button.setBounds(100,100,200, 40);
    frame.add(button);  
          
    frame.setSize(400,500);
    frame.setLayout(null);
    frame.setVisible(true);
  }  
}

Compile with: javac SwingExample.java
Run with: java SwingExample

Take a look at memory usage (in MB):

ps afu | awk 'NR>1 {$5=int($5/1024)"M";}{ print;}' | grep SwingExample

On my system:

andy 84842 0.0 0.0 6M 2272 pts/6 S+ 13:28 0:00 \_ grep SwingExample
andy 83086 0.2 0.2 10418M 70112 pts/4 Sl+ 13:24 0:00 \_ java SwingExample

Don’t get me wrong - many awesome desktop apps have been written with Java, such as LibreOffice, Eclipse, IntelliJ (Android Studio) etc…All I’m saying is it’s not a magical solution. Sometimes it just doesn’t make sense to roll with Java (and one of the many Java GUI frameworks out there), although sometimes it does :slight_smile:

1 Like

And just for fun:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

final public class Test
{
    final static int width = 500;
    final static int height = 500;
    float x1, y1, x2, y2;

    float r = 43f, g = 13f, b = 100f;
    float dr = 0.2f, dg = 0.3f, db = 0.4f;

    int linecount = 0;
    int counter = 0;

    List<MyLine> lines = new CopyOnWriteArrayList<>();

    JFrame frame;
    DrawPanel drawPanel;

    public static void main(String... args)
    {
        new Test().run();
    }

    private void run()
    {
        frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        drawPanel = new DrawPanel();
        frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
        frame.setResizable(false);
        frame.setSize(width, height);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        mainLoop();
    }

    class DrawPanel extends JPanel
    {
        @Override
        public void paintComponent(Graphics g)
        {
            g.setColor(new Color(200, 200, 200));
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            g.setColor(Color.BLACK);
            g.fillRect(6, 6, this.getWidth() - 12, this.getHeight() - 12);

            for (MyLine line : lines) {
                Color color = new Color(line.r, line.g, line.b);
                g.setColor(color);
                g.drawLine((int) line.x1, (int) line.y1, (int) line.x2, (int) line.y2);
            }
        }
    }

    private void mainLoop()
    {
        while (true)
        {
            counter = ((counter + 1) % 360);

            float scale = (float)width / 2;
            float offset = (float)width / 2;

            x1 = (float)Math.cos(Math.toRadians(counter) * 2) * scale + offset;
            y1 = (float)Math.sin(Math.toRadians(counter) * 3)  * scale + offset;
            x2 = (float)Math.cos(Math.toRadians(counter)) * scale + offset;
            y2 = (float)Math.sin(Math.toRadians(counter)) * scale + offset;

            r = r + dr; if (r >= 254 || r <= 1) dr = -dr;
            g = g + dg; if (g >= 254 || g <= 1) dg = -dg;
            b = b + db; if (b >= 254 || b <= 1) db = -db;

            MyLine line = new MyLine(x1, y1, x2, y2, (int)r, (int)g, (int)b);
            lines.add(line);
            linecount++;
            if (linecount > 50) {
                lines.remove(0);
            }

            try { Thread.sleep(10); } catch(Exception e) {}

            frame.repaint();
        }
    }

    static class MyLine
    {
        public float x1, y1, x2, y2;
        public int r, g, b;
        MyLine(float x1, float y1, float x2, float y2, int r, int g, int b) {
            this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2;
            this.r = r; this.g = g; this.b = b;
        }
    }

}

Save as: Test.java
Compile with: javac Test.java
Run with: java Test

:slightly_smiling_face:

1 Like

So…

What about packaging Java apps as an AppImage, with a JRE inside?

1 Like

As of Java 9 (some years ago now, I think) the JRE has been split into modules. This means packages compiled for distribution can be smaller. Also the fact that OpenJDK seems to be more prevalent on Linux that the Oracle build of Java, it’s possible that the JRE is being bundled in systems like AppImage now.

One of my favourite Java apps, Freeplane, which I have been using for notes / mindmaps for close to a decade now (and it’s a fork of Freemind which I was using for years before that) is now available as a flatpak, so I’m guessing it either packages a JRE inside the flatpak or uses a flatpak runtime of the JRE.