There is recently an increased interest to ease the learning curve of Java for students on Day 1 of class. Brian Goetz (the architect of Java) made a proposal to eliminate some code. My proposition is a (independent) continuation to ease the learning of Java.
Day 1 (as proposed by Brian Goetz)
class HelloWord {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
Simplifies to
void main() {
println("Hello World");
}
Day 2 (as proposed by me – Anthony Goubard)
import javax.swing.*;
void main() {
SwingUtilities.invokeAndWait(() -> {
JFrame frame = new JFrame("Test");
frame.add(new JLabel("Hello World"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Simplifies to
import javax.swing.*;
void main() {
SwingUtilities.showInFrame("Test", () -> new JLabel("Hello World"));
}
The on-ramp
- No need to understand the concept of the Event Dispatch Thread (EDT) where UI operations should be done
- No need to understand yet the concept of laying out components (
pack()
) - No need to know the class
JFrame
and 5 of its methods - The focus is more on the intention of the program: Showing the text “Hello World” in a window with title “Test”
Other benefits (than the on-ramp)
- Cleaner Stack overflow Swing examples.
- Ease of use with JShell.
- Event Dispatch Thread detection. Let’s face, it when it’s a small program, a lot of people forget to do the UI in the EDT.
- Single Java execution
java HelloWorld.java
would require less code. - No language or compiler change needed.
Proposed implementation
// public domain license - Should be in SwingUtilities
/**
* Show a window containing the provided component.
* The window will exit the application on close.
*
* @param title the title of the window
* @param panel the supplier for the component to show in the window
* @return the created component
*/
public static <T extends JComponent> T showInFrame(String title, Supplier<T> panel) {
Function<T, JFrame> frameSupplier = createdPanel -> {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createdPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
return frame;
};
boolean isInEDT = SwingUtilities.isEventDispatchThread();
if (isInEDT) {
T createdPanel = panel.get();
frameSupplier.apply(createdPanel);
return createdPanel;
} else {
List<T> result = new ArrayList<>();
List<Exception> exception = new ArrayList<>();
try {
SwingUtilities.invokeAndWait(() -> {
try {
T createdPanel = panel.get();
frameSupplier.apply(createdPanel);
result.add(createdPanel);
} catch (Exception ex) {
exception.add(ex);
}
});
} catch (InterruptedException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
if (!exception.isEmpty()) {
Exception ex = exception.get(0);
if (ex instanceof RuntimeException) throw (RuntimeException) ex;
else throw new RuntimeException(ex);
}
return result.get(0);
}
}
Advanced
The created component is returned so you can use it further in your code. With the returned component, you also have access to the created JFrame
by using SwingUtilities.windowForComponent
method.
I’ve decided to wrap the exception in a RuntimeException
is there is an error during the creation of the component. So you get a similar behavior whether you call this method from the Event Dispatch Thread or not.
Even though the example is with a JLabel
, I would expect most of the usage will be passing a Suppier<JPanel>
and probably like MyPanel::new
as it’s quite common in Swing to have classes extending JPanel
.
Another possibility would be to return void
and use SwingUtilities.invokeLater()
method. This way no need to do all the exception code and no need to have List<T> result
. Comment in the reddit discussion if it’s your preference (Link below).
My history
Back when I was a student (1995), I remember it took me half a day to try to show a window on Windows 95 as I was using Borland C++. I copied the code word by word from a book as otherwise it wouldn’t work. A few days later while asking a teacher if we could have an interesting project, he told us “Sun Microsystem has just released a new language, it’s in alpha version but let’s do a project with it.”. I took the language, typed Frame frame = new Frame("Test"); frame.show();
and voilà! It was a whoa moment where I realized I would spend a lot of time with this language 😃.
Conclusion
Quite often, you see in conferences presentations about “what’s new in Java xx”, that we may forget that for some people everything is new. Paving the on-ramp doesn’t have to be a compiler or language change, it could be methods, documentation, videos, …
I think the next step would be to create a RFE ticket in the JDK bug system, but first I will wait for comments in the reddit discussion.
- Follow the discussion on reddit
- My twitter