Saltar al contenido

Gestión de ingresos y gastos.

En este ejercicio de programación orientada a objetos (POO), vamos a crear una aplicación de consola para la gestión de ingresos y gastos personales.

Esto lo conseguiremos a través de un menú de opciones en el que seleccionaremos la operación que deseemos realizar. Para desarrollar este programa, vamos a seguir el diagrama de clases que se nos muestra a continuación.

diagrama de clases para la gestión de ingresos y gastos
POO. Diagrama de clases. Gestión de gastos e ingresos.

Si nos damos cuenta, en el diagrama, aparecen diferentes símbolos delante de cada atributo y cada método que nos indica su visibilidad. Vamos a describir que significa cada símbolo.

  • El más (+): El atributo o método es público, (public).
  • El menos (-): Nos indica que el atributo o método es privado, (private).
  • La almoadilla (#): Quiere decir que la visibilidad del método o atributo es protegido, (protected).
  • Este símbolo (~): Hace referencia a la visibilidad del paquete.

Una vez que ya sabemos como funciona la visibilidad de los métodos y atributos de una clase dentro de un diagrama de clases en la POO, lo primero que tenemos que hacer es analizar y desglosar nuestro diagrama.

Índice de contenidos

    Desglosando el diagrama de clases. Parte 1. Herencia de ingresos y gastos.

    Empezaremos explicando las tres primeras clases de las que se compone este ejercicio de gestión ingresos y gastos con POO en java.

    herencia en la gestión de ingresos y gastos
    diagrama de clases POO

    Por un lado, en esta primera parte, vemos tres clases:

    • Una clase Dinero: Si nos fijamos, esta clase es una clase abstracta que contiene 2 atributos protegidos (protected) y 3 métodos públicos. Además debemos tener en cuenta que ninguno de los métodos nos dice que tenga que ser abstracto. Esto es algo que nos puede confundir, pero cuando trabajamos con clases abstractas, hay que tener en cuenta una serie de aspectos que puedes encontrar accediendo a nuestra guía de java.

    ¿Quieres aprender java desde cero?

    Por otro lado, tenemos una clase Gasto y una clase Ingreso. Como podemos comprobar, estas clases no poseen ningún atributo, pero cada una de ellas, contiene un método constructor que recibe dos parámetros. Esto lo sabemos porque el nombre de los métodos de las clases Gasto e Ingreso, se llaman igual que sus clases.

    En segundo lugar, cada uno de los métodos, entre paréntesis contiene dos variables con un tipo de dato. Esto nos indica que el método constructor es un método que recibe parámetros.

    Por último, tanto la clase Ingreso, como la clase Gasto, posen un método toString. Este es un método getter, que devuelve una cadena de tipo String. Debes saber que el método toString es un método perteneciente a la clase Object. Por tanto, cuando queremos implementar este método en nuestras clases personalizadas, debemos indicar que es un método sobreescrito. Esto lo haremos con la palabra reservada en java @Override.

    Herencia entre clases en la POO

    Otro punto importante es que, tanto la clase Gasto, como la clase Ingreso, están unidas a la clase dinero a través de una flecha hacia arriba. Esto quiere decir, que la clase Ingreso y la clase Gasto, heredarán de la clase dinero. Es decir, también en este programa de java, aplicaremos el concepto de herencia.

    En POO, cuando una clase, hereda de otra, en este caso, tanto la clase Ingreso como Gasto heredan de dinero, entones, las dos clases (Ingreso y gasto), tendrán sus métodos propios (en este caso los diferentes constructores y su método toString propio) y además, podrán hacer uso de los métodos getDinero, setDinero, getDescripcion y setDescripcion, ya que estos los heredará de la clase padre. En este caso, la clase padre de las clases Ingreso y Gasto, es la clase dinero.

    Teniendo en cuenta esto, lo primero que vamos a hacer es crear las clases Dinero, Gasto e ingreso con sus métodos getter y setter.

    Creación de la clase Dinero para la gestión de ingresos y gastos.

    Según nuestro diagrama de clases, la clase Dinero, quedaría de la siguiente manera. Hay que tener en cuenta que esta clase es una clase abstracta

    package gestioncuentas;
    
    public abstract class Dinero {
    
        protected double dinero;
        protected String description;
    
        public void setDinero(double dinero) {
            this.dinero = dinero;
        }
        
        public void setDescription(String description) {
            this.description = description;
        }
    
        public double getDinero() {
            return dinero;
        }
    
        public String getDescription() {
            return description;
        }
    }
    

    Crear la clase Ingreso.

    Como ya hablamos antes, la clase Ingreso hereda de la clase dinero. Por lo tanto haremos uso de la cláusula extends para indicar que esta clase hereda de Dinero.

    package gestioncuentas;
    
    public class Ingreso extends Dinero {
    
        public Ingreso(double ingreso, String description) {
            this.dinero=ingreso;
            this.description=description;
        }
    
        @Override
        public String toString() {
            return "Ingreso a su favor en concepto de " + this.description
                    + ". Importe total: " + this.dinero ;
        } 
    }
    

    Creando la clase Gasto.

    En este caso pasa como en el caso anterior, esta clase hereda de la clase Dinero, por lo tanto usaremos la cláusula extends para indicar que esta clase Gasto hereda también de dinero.

    package gestioncuentas;
    
    public class Gasto extends Dinero {
    
        public Gasto(double gasto, String description) {
            this.dinero=gasto;
            this.description=description;
        }
    
        @Override
        public String toString() {
            return "Gasto en concepto de " + this.description
                    + ". Importe total: " + this.dinero ;
        }  
    }
    

    Desglose del diagrama de clases. Parte 2. Clases independientes de la gestión de ingresos y gastos.

    En esta segunda parte de la explicación de nuestro diagrama de clases, veremos el resto de clases que forman parte de la aplicación de gestión de ingresos y gastos. Vamos a ver la siguiente imagen.

    clases independientes sin herencia en la gestion de ingresos y gastos
    Clases independientes del diagrama de clases

    En este caso, tenemos tres clases independientes, las cuales no heredan ni de la clase Gasto ni de la clase ingreso. Las clases independientes serían:

    • La clase Usuario: Tiene sus atributos privados (características) y sus métodos públicos (lo que el usuario puede hacer).
    • Una clase Cuenta: Con sus características y métodos igual que la clase Usuario.
    • La clase GastoException: Esta clase no tiene ningún atributo, pero si un método constructor de tipo público. El motivo de tener que crear esta clase es porque el ejercicio, más adelante nos manda generar una excepción personalizada. Por otro lado, aunque el ejercicio no dice nada, esta clase heredará de la clase Exception.

    Vamos a explicar cada una de las clases por separado.

    Entendiendo la clase Usuario.

    Esta clase será la encargada de gestionar un único usuario. Este se creará al inicio del programa leyendo datos por el teclado.

    El DNI deberá tener un formato concreto. Está comprobación la realizará en una función setter y getter al mismo tiempo. Es decir, recibirá un DNI como parámetro y devolverá un booleano. True si es correcto y False si no lo es.

    El formato correcto debe cumplir las siguientes condiciones:

    • Los primeros 8 caracteres sólo podrán ser numéricos.
    • El último caracteres deberá ser una letra entre la A y la Z.
    • El guion entre los números y la letra es opcional admitiendo ambas
    • posibilidades. Por ejemplo:
      • DNI: 78844112L
      • DNI: 78844112-L
    • Tendrá una función toString con la que devolver su contenido.

    Composición de la clase usuario.

    Para crear esta clase, el diagrama nos indica que debemos implementar los siguientes métodos:

    • Usuario(): Es el constructor de la clase.
    • String getNombre(): Es un método get, que devolverá el nombre del usuario, es decir, devolverá una cadena de texto (String).
    • setNombre(String nombre): Es un método set, que establece el nombre del usuario. Este método, recibe por parámetro o argumento una cadena de texto que llamaremos nombre y que el usuario introducirá por teclado.
    • int getEdad: Es un método getter que devolverá un número entero, en este caso, devolverá la edad del usuario.
    • setEdad(int edad): Es un método setter que establecerá la edad del usuario y que recibirá por parámetro un valor de tipo numérico llamado edad y que el usuario introducirá por teclado.
    • String getDNI(): Es un método getter que devolverá una cadena de texto con el DNI del usuario.
    • boolean setDNI(String dni): Este método es un setter, es decir, establece un valor al dni, recibiendo lo que el usuario introduce por teclado en formato de cadena de texto. Por otro lado, devolverá true si el formato es correcto y false si no lo es. Este es un método que podemos decir que funciona a la vez de set (establece el valor) y get (devuelve un resultado).
    • String toString: Este es un método que hereda de la clase object y que puede sobreescribirse en cualquier clase que creemos.

    Programación de la clase Usuario.

    package gestioncuentas;
    
    public class Usuario {
        String nombre;
        String dni;
        int edad;
    
        // Metodo constructor para dar un estado inicial al objeto Usuario.
        public Usuario() { 
            this.nombre="";
            this.dni="";
            this.edad=0;
        }
    
        // Metodos setter (establecen valores)
        public void setNombre(String nombre) { // Establece el nombre
            this.nombre = nombre;
        }
        
        public void setEdad(int edad) { // Establece la edad
            this.edad = edad;
        }
        
        public void setDni(String dni) { // Establece el DNI
            this.dni = dni;
        }
        
        // Este metodo es getter (devuelve un valor) pero
        // también es un setter (establece un valor)
        // Este método comprueba si el DNI es correcto.
        public boolean setDNI(String dni){
            
            if(dni.matches("^[0-9]{8}[a-zA-Z]$")
                    || dni.matches("^[0-9]{8}[-][a-zA-Z]$")){
                this.dni=dni;
                return true;
            }
            else{
                return false;
            }      
        }
    
        // Métodos getter (devuelven un valor).
        public String getNombre() { // Devuelve el nombre
            return nombre;
        }
    
        public String getDni() { // Devuelve el DNI
            return dni;
        }
    
        public int getEdad() { // Devuelve la edad
            return edad;
        }
    
        // Metodo sobreescrito toString
        @Override
        public String toString() {
            return "Nombre: " + this.nombre + ".\n" +
                    "DNI: " + this.dni + ".\n" +
                    "Edad: " + this.edad + ".";
        }
    }
    

    Desarrollando la clase Cuenta.

    En esta clase, se gestionarán todos los movimientos de dinero tanto
    ingresos como gastos.

    • Inicialmente (en el constructor) se recibirá el usuario que es dueño de la cuenta y el saldo inicial que será de 0€.
    • Al añadir un nuevo ingreso se sumará al saldo de la cuenta, sabiendo que esta variable (la variable saldo), mostrará nuestro dinero real. Además la función devolverá el saldo total que tenemos en la cuenta.
    • Al añadir un nuevo gasto se debe comprobar si se dispone de saldo suficiente.
      • En caso contrario, se deberá lanzar una nueva excepción del tipo GastoException() pero el programa no debe finalizar.
      • Si se dispone de saldo suficiente se restará el importe del gasto y se devolverá el saldo de la cuenta.
    • Las funciones getGastos y getIngresos nos devolverán todos los movimientos de uno u otro tipo.
    • Además esta clase, tendrá una función toString que devolverá el usuario y su saldo.

    Composición de la clase cuenta.

    Según el diagrama, la clase cuenta, contará con los siguientes métodos:

    • Cuenta(): Constructor de la clase, que según nuestro enunciado, recibirá por parámetro un objeto de tipo Usuario y además, establecerá el saldo inicial en cero euros.
    • double getSaldo(): Es un método getter que devolverá el saldo de la cuenta.
    • setSaldo(double saldo): Es un método setter que establecerá el saldo de la cuenta recibiendo por parámetro un valor de tipo decimal llamado saldo.
    • Usuario getUsuario(): Método getter que devolverá el usuario de la cuenta.
    • setUsuario(Usuario usuario): Es un setter que establecerá el usuario de la cuenta. Recibe por parámetro un objeto de tipo Usuario llamado usuario.
    • double addIngresos(String descripcion, double cantidad): Es un método getter, ya que devuelve un valor de tipo double (decimal) que se refiere al saldo, pero a la vez en un método setter, ya que en este método se sumará el saldo del ingreso al saldo de la cuenta. Recibe por parámetro dos argumentos, la descripción del movimiento que se realiza y el importe del mismo.
    • double addGastos(String descripcion, double cantidad): Es un método getter, ya que devuelve un valor de tipo double (decimal) que se refiere al saldo, pero a la vez en un método setter, ya que en este método se restará el saldo del gasto del saldo de la cuenta. Recibe por parámetro dos argumentos, la descripción del movimiento que se realiza y el importe del mismo.
    • List<Ingreso> getIngresos(): Es un método getter. Este método devuelve una lista de objetos tipo Ingreso (tanto su concepto como su importe).
    • List<Gasto> getGastos(): Es un método getter. Este método devuelve una lista de objetos tipo Gasto (tanto su concepto como su importe).
    • String toString(): Este es un método getter sobreescrito y que hereda de la clase object. Este método puede sobreescribirse siempre que queramos en nuestras propias clases.

    Programación de la clase cuenta para la gestión de ingresos y gastos.

    package gestioncuentas;
    
    import java.util.*;
    
    public class Cuenta {
    
        private double saldo; // Saldo de la cuenta
        private Usuario usuarioCuenta; // Usuario propietario de la cuenta
        private List<Gasto> gastos; // Lista de gastos
        private List<Ingreso>ingresos; // Lista de ingresos
    
        // Contructor del objeto cuenta. Le da un estado iniciar a la cuenta.
        public Cuenta(Usuario usuarioCuenta) {
            this.usuarioCuenta=usuarioCuenta;
            this.saldo=0;
            this.gastos=new ArrayList<Gasto>();
            this.ingresos=new ArrayList<Ingreso>();
        }
    
        // Establece el usuario de la cuenta
        public void setUsuarioCuenta(Usuario usuarioCuenta) {
            this.usuarioCuenta = usuarioCuenta;
        }
    
        // Establece el saldo de la cuenta.
        public void setSaldo(double saldo) {
            this.saldo = saldo;
        }
        
        // Devuelve el saldo de la cuenta
        public double getSaldo() {
            return saldo;
        }
        
        // Devuelve el usuario de la cuenta
        public Usuario getUsuarioCuenta() {
            return usuarioCuenta;
        }
        
        // Devuelve la lista de gastos
        public List<Gasto> getGastos() {
            return gastos;
        }
        
        // Devuelve la lista de ingresos
        public List<Ingreso> getIngresos() {
            return ingresos;
        }
        
        // Agrega un ingreso a la lista.
        public double addIngresos(String description, double cantidad){
            
            // Se crea el ingreso y se pasa el importe y la descripcion.
            Ingreso nuevoIngreso = new Ingreso(cantidad,description);
            // Se agrega el ingreso a la lista
            this.ingresos.add(nuevoIngreso);
            // Se suma el saldo
            this.saldo=this.saldo+cantidad;
            // se devuelve el saldo
            return saldo;
        }
        
        // Agrega un gasto a la lista
        public double addGastos(String description, double cantidad){
            
            try{ // Intentamos
                // Restar el saldo
                this.saldo = this.saldo-cantidad;
                
                if(this.getSaldo()<0){ // Si el saldo es menor que cero
                    // Lanzamos la excepción personalizada
                    throw new GastoException();
                }
                // Al lanzar la excepción se ejecuta el catch.
            }catch(GastoException e){
                // Devolvemos un -1
                return -1;
            }
            // Si no ejecuta el catch ejecutará lo siguiente
            // Creamos un nuevo gasto
            Gasto nuevoGasto=new Gasto(cantidad,description);
            // Lo agregamos a la lista de gastos
            gastos.add(nuevoGasto);
            // Devolvemos el saldo
            return saldo;
        }
        
        @Override
        public String toString(){
            return "Hola " + this.usuarioCuenta.getNombre() + ", el saldo de tu "
                    + "cuenta es " + this.saldo;
        }
    }
    

    Implementando nuestra propia excepción. Clase GastoException().

    Esta clase nos servirá para implementar nuestra propia excepción. Como bien se nos indica en el diagrama de clases, contendrá un constructor vacío.

    Código de la clase GastoException.

    package gestioncuentas;
    
    public class GastoException extends Exception {
    
        // Declaramos una variable para almacenar el mensaje de error
        private String error="";
        public GastoException() {
            // Construimos la excepción.
            this.error="No se puede agregar el gasto ya que el saldo es menor que "
                    + "el importe del gasto, o su saldo es cero euros.";
        }
        
        // Sobreescribimos el metodo getMessage
        @Override
        public String getMessage(){
            return error;
        }    
    }
    

    Creación del usuario y sus datos.

    Primero, crearemos una clase llamada Principal, que contendrá el método main, encargado de arrancar el programa. El funcionamiento de la aplicación seguirá los siguientes pasos:

    Lo primero será crear un usuario cuando arranca la aplicación. Como ya sabemos, en el momento que creamos una clase en java, ya podemos crear objetos de esa clase. Anteriormente, ya habíamos creado la clase usuario con sus propiedades y lo que el objeto puede hacer.

    Ahora vamos a crear un nuevo objeto usuario y pedir sus datos por teclado a través de un método llamado pedirDatosUsuario(). Recordar que también se debe importar el paqute java.util para poder utilizar la clase Scanner.

    Variables del método de la creación del usuario.

    package gestioncuentas;
    
    import java.util.Scanner;
    
    public class GestionCuentas {
    
        // ------------VARIABLE PARA LEER DATOS INTRODUCIDOS -------------------//
        // Creamos una variable Scanner para leer datos por teclado
        private static final Scanner lectura = new Scanner(System.in);
        
        //********************************************************************//
        // --------------VARIABLES PARA LA CLASE USUARIO -------------------//
        /* Creamos una variable privada llamada nuevoUsuario.
        Esta variable almacenará objetos de tipo Usuario.
        Para ello usaremos la palabra reservada new */
        private static Usuario nuevoUsuario = new Usuario();
        
        // Declaramos una variable para almacenar el nombre del usuario
        private static String nombreUsuario="";
        
        // Declaramos una variable para almacenar la edad del usuario
        private static String edadUsu="";
        
        /* Declaramos una variable para almacenar la edad del usuario
        en un formato numérico*/
        private static byte edadUsuario=-1;
        
        // Declaramos una variable para almacenar el dni del usuario
        private static String dniUsuario="";
        
        /* Declaramos una variable para validar que el usuario creado es correcto
        La iniciamos en falso porque a estas alturas del programa todavia no
        se han pedido datos de usuario*/
        private static boolean usuarioCreado=false;
    

    Programando el método de creación del usuario.

    Este método pedirá los datos de usuario por teclado y si son correctos la varieble usuarioCreado le asignaremos true. En caso contrario la variable será false.

        // METODO QUE PIDE LOS DATOS PARA CREAR UN USURIO
        private static void pedirDatosUsuario(){
            usuarioCreado=false;
            // Pedimos el nombre de usuario y repetimos la operación mientras que
            // el nombre del usuario tenga una cadena vacía.
            do{
                System.out.println("Introduce el nombre del usuario");
                nombreUsuario=lectura.nextLine().toUpperCase();
            }while(nombreUsuario.isEmpty());
            nuevoUsuario.setNombre(nombreUsuario);
            
            /* Pedimos la edad de usuario y repetimos la operación mientras que
            la edad del usuario (edadUsu) sea una cadena vacía, o mientras la
            edad del usuario en formato numérico sea mayor que cero*/
            do{
                System.out.println("Introduce la edad del usuario");
                edadUsu=lectura.nextLine();
                // Intentamos pasar la edad del usuario a formato numérico
                try{
                    edadUsuario = Byte.parseByte(edadUsu);
                    nuevoUsuario.setEdad(edadUsuario);
                }catch(NumberFormatException e){
                    System.out.println("La edad debe numérica y mayor que cero");
                }
            }while(edadUsu.isEmpty() || edadUsuario<=0);
            
            
            /* Pedimos el DNI del usuario y repetimos la operación mientras que
            la variable dniUsuario tenga una cadena vacía o siempre que el
            metodo setDNI de tipo booleano devuelva falso*/
            do{
                System.out.println("Introduce el DNI del usuario");
                dniUsuario=lectura.nextLine().toUpperCase();
                
                /* Si el valor es correcto se establece el valor del DNI
                a la variable dni de la clase (objeto) Usuario*/
                if(nuevoUsuario.setDNI(dniUsuario)){
                    nuevoUsuario.setDNI(dniUsuario);
                }
                else{
                    System.out.println("El DNI introducido no es correcto."
                            + "Vuelva a introducir el DNI");
                }
            }while(dniUsuario.isEmpty() || nuevoUsuario.setDNI(dniUsuario)==false);
            
            // Si todo está correcto, validamos el usuario
            usuarioCreado=true;
        }
    

    Una vez que se ha creado el usuario, se debe crear una cuenta pasándole el usuario creado por parámetro para que pueda agregar sus ingresos y gastos. (Esto lo haremos en el método main que mostraremos más adelante).

    Por el momento, vamos a imaginar que tenemos la cuenta creada. Entonces si tuviéramos la cuenta ya creada, debemos mostrar un mensaje por pantalla con las operaciones que el usuario puede realizar. Vamos a ver como hacerlo.

    Programando el menú de opciones para la gestión de ingresos y gastos.

    Lo primero que debemos hacer es crear una variable de tipo texto que almacenará lo que el usuario introduce por teclado y que llamaremos opcion. A continuación, se creará una variable llamada numeroOpcion de tipo entero. Esta variable almacenará la opción que el usuario selecciona.

    Variables para la creación del menú de opciones.

    //********************************************************************//
        // ------------VARIABLE PARA LEER OPCIONES DEL MENÚ -------------------//
        /* Declaramos una variable de tipo String que almacenará la opción
        que elija el usuario en formato texto y le asignaremos un valor vacío
        ya que, si no lo hacemos así la variable no tendrá ningún valor,
        ni siquiera cero. */ 
        private static String opcion = "";
        
        /* Declaramos una variable de tipo byte para almacenar en formato numérico
        el valor que el usuario está introduciendo en formato texto*/
        private static byte numeroOpcion= -1;
    

    A continuación crearemos un método llamado mostrarMenu(). Este método, mostrará el menú y pedirá por teclado una opción al usuario hasta que introduzca una opción correcta. Esto lo hará una vez que la función sea llamada desde el método main.

    Método para la creación e interacción con el menú de opciones.

    // METODO QUE MUESTRA EL MENÚ DE OPCIONES, PIDE UNA OPCIÓN AL USUARIO
        // E INTENTA PASAR LA OPCION INTRODUCIDA EN TEXTO A FORMATO NUMÉRICO.
        private static void mostrarMenu(){
            
            do{
            System.out.println("1. Introducir un nuevo gasto");
            System.out.println("2. Introducir un nuevo ingreso");
            System.out.println("3. Mostrar gastos");
            System.out.println("4. Mostrar ingresos");
            System.out.println("5. Mostrar saldo de la cuenta");
            System.out.println("0. Salir");
            
            try{
            
                // Informamos al usuario que elija una opción.
                System.out.print("Introduce una opción del menú: ");
    
                // Leemos lo que el usuario ha introducido por teclado
                // y lo guardamos en la variable opción
                opcion = lectura.nextLine();
                
                /* Passamos el valor de tipo String a tipo byte. Esto lo hacemos
                para asegurarnos de que el usuario ha introducido un número
                y no un texto */
                numeroOpcion = Byte.parseByte(opcion);
            }
            catch(NumberFormatException e){
                System.out.println(e.getMessage());
                System.out.println("La opción elegida debe ser un número "
                        + "entre 0 y 5");
            }
            }while(numeroOpcion<0 && numeroOpcion>5);
        }
    

    Una vez ya se ha creado el usuario y la cuenta, se mostrará el menú. Ahora crearemos un método para cada una de las opciones. El código estará comentado para una mejor comprensión.

    Tanto para agregar gastos como ingresos, necesitamos declarar una serie de variables para almacenar los conceptos y las descripciones de los movimientos.

    Estás variables almacenarán lo que el usuario introduce. Después a través de los métodos correspondientes de la clase cuenta (que gestiona todos los movimientos), haremos funcionar la aplicación.

    Variables de la clase cuenta para gestionar gastos e ingresos.

    // --------------VARIABLES PARA LA CLASE CUENTA -------------------//
        
        /* Declaramos una variable que va a almacenar un objeto de tipo Cuenta
        en una variable llamada nuevaCuenta. De momento le asignamos un valor null
        */
        private static Cuenta nuevaCuenta = null;
        
        /* Declaramos una variable de tipo texto (String)
        donde almacenaremos el importe del gasto o ingreso*/
        private static String importe="";
        
        /* Declaramos una variable de tipo double (decimal)
        donde almacenaremos el importe del gasto o ingreso
        convertido en formato numérico decimal tipo double*/
        private static double importeTotal=0;
        
        /* Declaramos una variable de tipo texto (String)
        donde almacenaremos el concepto del gasto o ingreso*/
        private static String descripcion="";
    

    Implementación del método para agregar gastos.

    // METODO QUE NOS PERMITIRÁ INTRODUCIR GASTOS EN LA CUENTA
        private static void introducirGastos(){
            
              // Reiniciamos las variables por si tuvieran algún valor.
            importe="";
            descripcion="";
            importeTotal=0;
            
             // Pedimos la descripción del gasto
            do{
                System.out.print("Introduce el concepto del gasto: ");
                descripcion = lectura.nextLine();
                
            }while(descripcion.isEmpty());
            
            // Pedimos la el importe del gasto
            do{
                System.out.print("Introduce el importe del gasto: ");
                importe = lectura.nextLine();
                
                try{ // Intentamos pasar el valor ingresado a formato numérico
                    importeTotal=Double.parseDouble(importe);
                }catch(NumberFormatException e){
                    System.out.println("El importe del ingreso debe ser numérico +"
                            + e.getMessage());
                } 
            }while(importe.isEmpty());
                
            // Si el saldo de la cuenta es cero, o es menor al importe del gasto
            if(nuevaCuenta.getSaldo()<importeTotal || nuevaCuenta.getSaldo()==0){
               
                // Por lo tanto, informamos al usuario que debe realizar un ingreso
                // antes de registrar el gasto.
                System.out.println("Debes realizar primero un ingreso para "
                        + "registrar un gasto");
            }
            else{ // En caso contrario
                
              // Agregamos el gasto a la cuenta
                nuevaCuenta.addGastos(descripcion, importeTotal);
    
                // Informamos al usuario que se ha registrado el gasto.
                System.out.println("Gasto registrado correctamente.");  
            }
        }
    

    Creación del método para agregar los ingresos.

     /* METODO QUE NOS PERMITIRÁ INTRODUCIR INGRESOS EN LA CUELTA*/
        private static void introducirIngresos(){
            
            // Reiniciamos las variables por si tuvieran algún valor.
            importe="";
            descripcion="";
            importeTotal=0;
            
            // Pedimos la descripción del ingreso
            do{
                System.out.print("Introduce el concepto del ingreso: ");
                descripcion = lectura.nextLine();
                
            }while(descripcion.isEmpty());
            
            // Pedimos la el importe del ingreso
            do{
                System.out.print("Introduce el importe del ingreso: ");
                importe = lectura.nextLine();
                
                try{ //Intentamos pasar el valor ingresado a formato numérico
                    importeTotal=Double.parseDouble(importe);
                }catch(NumberFormatException e){
                    System.out.println("El importe del ingreso debe ser numérico +"
                            + e.getMessage());
                }
            }while(importe.isEmpty());
            
            // Agregamos el ingreso a la cuenta
            nuevaCuenta.addIngresos(descripcion, importeTotal);
            
            // Informamos al usuario
            System.out.println("Ingreso registrado correctamente");
        }
    

    Mostrar los gastos a través del método mostrarGastos()

    private static void mostrarGastos(){
            
            // Si la lista de gastos no está vacia
           if(!nuevaCuenta.getGastos().isEmpty()){
                // Recorremos la lista de gastos
               for(int x=0;x<nuevaCuenta.getGastos().size();x++){
                   System.out.println(nuevaCuenta.getGastos().get(x).toString());
               }
           }
           else{ // En caso de que la lista esté vacía informamos al usuario
               System.out.println("No existen gastos en esta cuenta.");
           }
        }
    

    Implementación del método para mostrar los ingresos.

    // METODO QUE NOS PERMITE MOSTRAR UNA LISTA DE INGRESOS DE LA CUENTA
        private static void mostrarIngresos(){
            
            // Si la lista de ingresos no está vacia
           if(!nuevaCuenta.getIngresos().isEmpty()){
                // Recorremos la lista de gastos
               for(int x=0;x<nuevaCuenta.getIngresos().size();x++){
                   System.out.println(nuevaCuenta.getIngresos().get(x).toString());
               }
           }
           else{ // En caso de que la lista este vacía, informamos al usuario
               System.out.println("No existen gastos en esta cuenta.");
           }
        }
    

    Codificación del método main.

    Debemos tener en cuenta que todos los métodos anteriores de mostrar ingresos y gastos y listar ambos movimientos, se encuentran en la clase principal, (la que contiene el método main). Una vez aclarado, veamos el código fuente del método para iniciar la aplicación en java.

       public static void main(String[] args) {
            
           /* Pedimos los datos para crear un usuario como mínimo una vez y hasta
           que el usuario se haya creado correctamente*/
            do{
               pedirDatosUsuario();
           }while(usuarioCreado=false);
            
            /* Si sale del bucle ya sabemos que el usuario está creado, entonces
            Mostramos los datos del usuario */
            System.out.println("Datos del nuevo usuario:");
            System.out.println(nuevoUsuario.toString());
            
            // Y creamos una nueva cuenta
            nuevaCuenta=new Cuenta(nuevoUsuario);
            
            /* Mostramos el menú como mínimo una vez.
            Tener en cuenta que la primera vez que se muestra el menú la variable
            numeroOpcion tiene un valor de -1 y el menú se mostrará mientras que
            la variable numeroOpcion sea diferente de cero.*/
            do{ 
                
                mostrarMenu();
    
                /* Creamos una estructura switch a través de la cual sabremos
                que opción se debe ejecutar en cada momento. */
                switch(numeroOpcion){
    
                    case 0: // Eligiendo un cero, saldrá del programa
                        System.out.println("Programa finalizado."
                                + "Gracias por utilizar la aplicación.");
                        break;
    
                    case 1: // Eligiendo un uno se registra un nuevo gasto
                        introducirGastos();
                        break;
    
                    case 2: // Eligiendo un dos se registra un nuevo ingreso
                        introducirIngresos();
                        break;
    
                    case 3: // Eligiendo un tres se muestran los gastos
                        mostrarGastos();
                        break;
    
                    case 4: // Eligiendo un cuatro se muestran los ingresos
                            mostrarIngresos();
                        break;
    
                    case 5: // Elige un cinco se muestra el saldo de la cuenta
                        System.out.println(nuevaCuenta.toString());
                        break;
    
                    default: // Con cualquier otro número, muestra un mensaje
    
                        System.out.println("Introduce el valor correcto");
                        break;
                }
    
            // Esto lo hará miestras el valor de la variable
            // numeroOpcion sea diferente de cero
            }while(numeroOpcion !=0);
            
            // Cerramos el objeto lectura, ya que si sale del bucle do - while
            // quiere decir que el programa finalizó.
            lectura.close();
        }
    

    DESCARGAR PROYECTO