Search code examples
javacompiler-constructionunchecked

What does it mean when my compiler tells me I'm using unsafe or unchecked operations?


My program compiles fine, but my console spits out the following:

 ----jGRASP exec: javac -g CreditGraphics.java

Note: CreditGraphics.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

 ----jGRASP: operation complete.

First, what makes an operation unsafe? And how can a process be "unchecked"? What does "Recompile with -Xlint" mean? I'm using jGrasp and I'm not sure if that's a button or some sort of command? I want to see the details. It doesn't specify what is unsafe or unchecked, but here's my code anyway:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.util.Scanner;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.event.*;
import javax.mail.internet.*;
import javax.activation.*;
import java.util.Properties;
import javax.mail.Header;
import java.util.Enumeration;
import java.util.Properties;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.JApplet;
import javax.mail.Authenticator;
import javax.mail.Folder;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.URLName;
import java.beans.*;
import java.util.ArrayList;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.*;
import java.util.Scanner;
import java.awt.image.*;
import java.io.*;
import java.net.URL;
import javax.imageio.*;
import javax.swing.Timer;

public class CreditGraphics {

    //first screen variables
    public String cardNum;
    public JFrame frame;
    public JPanel panel;
    public JLabel label;
    public JTextField text;
    public String cardType = "";
    public String carddigits;
    public boolean cardValid;
    public int length;
    public String[] cardTypes;
    public JComboBox cardTypesDD;
    public static ArrayList<Integer> holdDigits = new ArrayList<Integer>();
    public static ArrayList<String> holdDigitsChar = new ArrayList<String>();
    public static int[] checkDigits;
    public static int checkSum = 0;

    //second screen variables in verifyScreen;
    public JFrame vframe;
    public JPanel vpanel;
    public JLabel titlelabel;
    public GridBagConstraints grid;
    public JLabel namelabel;
    public JTextField namefield;

    public CreditGraphics() {

        frame = new JFrame("MES Banking App");
        panel = new JPanel();
        label = new JLabel();
        cardTypes = new String[4];
        cardTypes[0] = "Visa";
        cardTypes[1] = "American Express";
        cardTypes[2] = "Master Card";
        cardTypes[3] = "";
        cardTypesDD = new JComboBox(cardTypes);
        cardTypesDD.setSelectedIndex(3);

        text = new JTextField(16);

        panel.add(label);
        panel.add(cardTypesDD);
        panel.add(text);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.setPreferredSize(new Dimension(500, 500));
        frame.getContentPane().add(panel);

        frame.pack();
        frame.setVisible(true);

        label.setText("<html>Please enter your credit card <br> 'Master Card' 'Visa' or 'American Express'</html>");

        text.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        //after CC type is entered, prompt user to enter digits
                        carddigits = text.getText();//gets credit card number from jtextfield
                        length = carddigits.length();//sets length of card
                        validateCard(); //uses credit card number and length to determine if it matches up to brand

                        //below returns if card is valid
                        if (cardValid == true) {
                            label.setText("Card brand is valid");
                        }
                        waits(1);

                        text.setText("");

                        waits(1);
                        checkDigits();

                    }

                });

        cardTypesDD.addActionListener( new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        //where program really starts
                        while (cardTypesDD.getSelectedIndex() == 3) {
                            label.setText("First, please select a card type from DD list");
                        }

                        cardType = (String) cardTypesDD.getSelectedItem();
                        System.out.println(cardType);

                        if (!cardType.equals("")) {
                            label.setText("Thank you, now please enter your card #");
                        }
                        //now go to the jtextfield actionlistener
                    }});
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(
                new Runnable() {
                    public void run() {

                        new CreditGraphics();

                    }});
    }

    public void verifyScreen() {
        //destroy old frame
        frame.dispose();

        //create new frame essentially same as last frame
        vframe = new JFrame("MES Banking App");
        vpanel = new JPanel();
        titlelabel = new JLabel("Verification Page");
        namelabel = new JLabel("Name: ");
        namefield = new JTextField(20);
        //title section
        vpanel.setLayout(new GridBagLayout());
        grid = new GridBagConstraints();
        grid.fill = GridBagConstraints.PAGE_START;
        grid.weightx = 0;
        grid.gridx = 0;
        grid.gridy = 0;
        vpanel.add(titlelabel, grid);

        //name section
        grid.gridy = 1;
        grid.insets = new Insets(10, 0, 0, 0);
        vpanel.add(namelabel, grid);
        grid.gridx = 1;
        grid.insets = new Insets(10, 10, 0, 0);
        vpanel.add(namefield, grid);

        vframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        vframe.getContentPane().add(vpanel);

        vframe.pack();
        vframe.setVisible(true);
    }

    public static void waits(int k) {
        long time0, time1;
        time0 = System.currentTimeMillis();
        do {
            time1 = System.currentTimeMillis();
        } while ((time1 - time0) < k * 1000);
    }

    public void validateCard() {
        //check brand

        cardValid = false;
        if ((cardType.equals("Visa") && carddigits.substring(0, 1).equals("4")) && (length == 13 || length == 16)) {
            label.setText("Thank you, next step");

            cardValid = true;
        }

        if ((cardType.equals("Master Card")) && (carddigits.substring(0, 2).equals("51") || carddigits.substring(0, 2).equals("52") || carddigits.substring(0, 2).equals("53") || carddigits.substring(0, 2).equals("54") || carddigits.substring(0, 2).equals("55")) && (length == 16)) {
            label.setText("Thank you, next step");
            cardValid = true;
        }

        if ((cardType.equals("American Express") && carddigits.substring(0, 2).equals("37") && length == 15)) {
            label.setText("Thank you, next step");
            cardValid = true;
        }

        if (cardValid != true) {
            System.out.println("ERROR");
            label.setText("ERROR");
            waits(2);
            System.exit(0);
        }
        //end check
    }

    public void checkDigits() {
        label.setText("Checking digits using Luhn's algorithm...");
        waits(2);
        //check digits
        checkDigits = new int[length];
        for (int i = 0; i < length; i++) {
            checkDigits[i] = Integer.parseInt(carddigits.substring(i, i + 1));

            //successfully puts digits into array
        }
        for (int e = length - 2; e >= 0; e -= 2) {
            checkDigits[e] = 2 * checkDigits[e];
        }
        for (int d = 0; d < length; d++) {
            holdDigitsChar.add(String.valueOf(checkDigits[d]));
        }
        for (int v = 0; v < length; v++) {
            if (holdDigitsChar.get(v).length() == 2) {
                holdDigits.add(Integer.parseInt(holdDigitsChar.get(v).substring(0, 1)));
                holdDigits.add(Integer.parseInt(holdDigitsChar.get(v).substring(1, 2)));
            } else {
                holdDigits.add(Integer.parseInt(holdDigitsChar.get(v)));
            }
        }

        for (int c = 0; c < holdDigits.size(); c++) {
            checkSum += holdDigits.get(c);
        }

        System.out.println("Check sum:" + checkSum);

        if (checkSum % 10 == 0) {
            label.setText("Numbers check out, thank you");
            waits(2);
            verifyScreen();
        } else {
            System.out.println("ERROR");
            System.exit(0);
        }
    }
}

Solution

  • This usually comes up if you're using collections or some other genericized object without generic parameters. For example:

    List l = new ArrayList();
    

    vs.

    List<String> l = new ArrayList<>(); //or new ArrayList<String>(); in Java < 7
    

    What this means is that the Java compiler cannot guarantee that you are using those collections in a type-safe way. For example, you should shove a String and an Integer into the ArrayList in the first scenario. At some point when you pull it out, there is a distinct possibility that you may attempt to cast the Integer instance into a String, which would result in a ClassCastException. You could, of course, be really, really, careful and not do this, but the compiler is simply alerting you to the fact that there is no way to guarantee what is inside that list.

    To get rid of this warning, use the second method of instantiation. If you are sure that you can get away with this (in some instances it is possible because you can be sure what the collection will contain) you can use the @SuppressWarnings("unchecked") annotation.