Better conditional statements

I don’t know if you are like me, but I really have a hard time reading complex ‘if’ statements with boolean expressions.

For example:

if ("male".equals(person.getGender()) && person.getAge()>=18 && !"french".equals(person.getNationality()) ||
 "female".equals(person.getGender()) && person.getAge()<18 && !"german".equals(person.getNationality()) {
 // do something
 }

If you are like me, my recommendation is to give explicit names to each expression, like this:

boolean isNonFrenchMaleAdult = "male".equals(person.getGender()) && person.getAge()>=18 && !"french".equals(person.getNationality());
boolean isNonGermanFemaleChild = "female".equals(person.getGender()) && person.getAge()<18 && !"german".equals(person.getNationality());

 if (isNonFrenchMaleAdult || isNonGermanFemaleChild) {
 // do something
 }

From there, it might also be interesting to make the conditional expressions part of the Person class to end up with:

if (person.isNonFrenchMaleAdult() || person.isNonGermanFemaleChild()) {
 // do something
 }

You can even go further and combine the 2 methods in a single one:

if (person.isEligibleToDoSomethingVeryInteresting()) {
 // do something
 }

Finally, why not completely move all the logic inside the Person class ?

person.doIt();

Note that in practice, you may not want to move all the logic inside the Person class.

For example, if the ‘if’ statement persists the Person instance in a database, you may not want to put the data access logic in the domain object.

Laurent KUBASKI

Button at bottom of dialog with MigLayout

MigLayout is a powerfull Swing layout manager.

However, when you are used to the standard J2SE layout managers, it can take a while to understand how to do something using MigLayout.

For example, I needed to create this UI:

As you can see, the idea is to leave the OK button at the button of the dialog, even when the dialog is resized.

My initial attempt was to use a fake panel as the third row:

public class TestResize extends JDialog {
protected JPanel contentPane;
public TestResize() {
   super((Dialog) null, "Test resize", true);
   setupUI();
   setContentPane(contentPane);
}
private void setupUI() {
   contentPane = new JPanel(new MigLayout());
   // first row
   contentPane.add(new JLabel("Enter size"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // second row
   contentPane.add(new JLabel("Enter weight"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // third row = fake panel that is allowed to grow
   contentPane.add(new JPanel(), "span 2, grow, pushy, wrap");
   // fourth row = panel with centered button
   JPanel buttonPanel = new JPanel(new MigLayout("", "[center, grow]"));
   buttonPanel.add(new JButton("Ok"), "");
   contentPane.add(buttonPanel, "dock south");
}
public static void main(String[] args) {
   TestResize dialog = new TestResize();
   dialog.pack();
   dialog.setVisible(true);
}
}

This works… but it’s not the correct way to do it using MigLayout: you need to use  the “push” constraint.

public class TestResize extends JDialog {
protected JPanel contentPane;
public TestResize() {
   super((Dialog) null, "Test resize", true);
   setupUI();
   setContentPane(contentPane);
}
private void setupUI() {
   // Layout is constructed with "push" constraint
   contentPane = new JPanel(new MigLayout("", "", "[][]push[]"));
   // first row
   contentPane.add(new JLabel("Enter size:"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // second row
   contentPane.add(new JLabel("Enter weight"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // third row = panel with centered button
   JPanel buttonPanel = new JPanel(new MigLayout("", "[center, grow]"));
   buttonPanel.add(new JButton("Ok"), "");
   contentPane.add(buttonPanel, "dock south");
}
public static void main(String[] args) {
TestResize dialog = new TestResize();
dialog.pack();
dialog.setVisible(true);
}
}

That’s it: no more crappy fake panel ! 🙂

Laurent KUBASKI

getResourceAsStream

You think that java.lang.Class.getResource(String name) is the same as java.lang.ClassLoader.getResource(String name) ? Think again…

The javadoc for java.lang.Class.getResource(String name) states that:

Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:

  • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
  • Otherwise, the absolute name is of the following form: modified_package_name/name where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').

Now compare this with the javadoc for java.lang.ClassLoader.getResource(String name) :

The name of a resource is a ‘/‘-separated path name that identifies the resource

Yes, this means that when using ClassLoader.getResource(String name), the path must NOT start with a ‘/’, and in the end, these 2 statements are similar:

this.getClass().getResource("/sub/file1.properties");

// note that there is no '/':

this.getClass().getClassLoader().getResource("sub/file2.properties");

Laurent KUBASKI

Searching a class in jar files

This post has moved

JTable tips

This post has moved