Variables i Scanner

En aquesta activitat aprendràs a fer programes interactius, que demanen dades i després les utilitzen.

Aprendràs:

Què són les variables i com utilitzar-les Com obtenir dades de l'entrada estàndard i guardar-les en variables

Tipus i variables

Declaració i inicialització

Una variable és un espai reservat a la memòria per a emmagatzemar valors d'un tipus particular: un string, un número, o altres. Cada variable té un nom (o identificador) per a distingir-la d'altres. Abans d'utilitzar una variable, l'has de declarar.

La forma general de declarar una variable és així:

TipusDada nomVariable = inicialitzacio;

La part esquerra d'aquesta sentència descriu la variable, i la part dreta descriu el valor que se li ha assignat.

D'acord amb això, podem declarar una variable de tipus String i assignar-li la paraula java:

String llenguatge = "java";

També podem declarar una variable de tipus int i guardar en ella un número enter:

int nombreDePomes = 5;

Lés majúscules i minúscules importen! No és el mateix llenguatge que Llenguatge.

Les variables no solament poden emmagatzemar strings i enters, sinò també caracters, booleans, decimals, i altres tipus que veurem més endavant.

Una forma habitual d’entendre les variables és imaginar una variable com una capsa on s’hi emmagatzema una dada o valor.


Així, hi ha capses de diferents colors, per a emmagatzemar diferents tipus de dades.
Per exemple, capses blaves per a String i capses verdes per a int:


A les capses se'ls hi ha de posar un identificador per a distingir-les. L'identificador ha de descriure la dada que s'hi guardarà.


Per exemple, si es volen guardar el nom i l'edat d'una persona, es poden tenir aquestes capses:


En cadascuna d'elles s'emmagatzema el valor corresponent:

String nom = "Joan"; int edat = 24;

És un error tractar de guardar un tipus de dada en el tipus de capsa inadequat:

int edat = "Joan"; // error!, la variable és int i el valor string

Per una altra banda, és vàlid posar els identificadors que desitjem a les capses, però s'entendrà millor si posem un nom que descrigui la dada que s'hi ha de guardar:

int nom = 24; // vàlid! però no té sentit ¿?¿?

Resol aquest problema:
Declaració invàlida de variables

Accedir al valor d'una variable

Un cop una variable ha estat declarada, el seu valor pot ser accedit i modificat utilitzant el seu nom (identificador). En aquest exemple, declarem una variable i després l'imprimim:

String diaDeLaSetmana = "Dilluns"; System.out.println(diaDeLaSetmana); // Dilluns

També es possible assignar el valor d'una variable a una altra variable. A la línia 2 d'aquest codi estem assignant a avui el valor de diaDelMes:

int diaDelMes = 25; int avui = diaDelMes; System.out.println(avui); // 25 System.out.println(diaDelMes); // 25

És important notar que no es perd el valor d'una variable quan l'assignem a una altra variable.

Una característica important de les variables és que el seu valor pot canviar. No s'ha de tornar a declarar la variable per a canviar-li el valor; únicament se li ha d'assignar el nou valor utilitzant l'operador =.

Anem a declarar una variable anomenada diaDeLaSetmana i imprimirem el seu valor abans i després de canviar-li'l:

String diaDeLaSetmana = "Dilluns"; System.out.println(diaDeLaSetmana); // Dilluns diaDeLaSetmana = "Dimarts"; System.out.println(diaDeLaSetmana); // Dimarts

Hi ha una restricció en les variables: només pots assignar un valor del mateix tipus que el tipus inicial de la variable. Així, el següent codi és incorrecte

int dia = 10; // ok dia = 11; // ok dia = "Dilluns"; // error! El tipus inicial era int

Recorda: una variable només pot tenir un únic valor a la vegada. És a dir, quan guardem un valor en una variable, el valor que tenia abans es sobreescriu:

int edat = 24; edat = 25;

Exercicis:
Assignacions
Completa la declaració

Formes alternatives de declaració

Hi han vàries formes alternatives de declarar variables que són menys utilitzades en la pràctica. Aquí hi han alguns exemples:

Tipus de variables

A la documentació oficial d'Oracle pots trobar els tipus de dades del llenguatge Java. En aquest curs utilitzarem més sovint els següents:

A la següent taula pots veure els valors que permeten guardar aquests tipus de dades:

TipusValors permesos
int un número enter (entre -2_147_483_648 i 2_147_483_647)
floatnúmero decimal (e.g. 123.975f)
booleanun booleà (true / false)
charun caracter (entre cometes simples, e.g. 'a')
Stringun string (entre cometes dobles, e.g. "java")

Aquí tens un exemple de declaració d'una variable de cada tipus:

int edat = 18; float notaMitjana = 8.75f; boolean estaMatriculat = true; char grup = 'A'; String email = "alumne@ins.com";

Inferència de tipus

A partir de Java 10, es pot escriure var en lloc d'un tipus específic per a forçar la inferència de tipus basada en el tipus del valor assignat.

var nomVariable = inicialització;

Aquí tens dos exemples:

var llenguatge = "java"; // String var versio = 10; // int

En aquest curs no utilitzarem la inferència de tipus, ja que utilitzarem fonamentalment la versió 8 de Java, que de moment segueix sent la més utilitzada.

Donada la següent declaració d'una variable:

String speed = "high";

Quin és el nom de la variable?

speed "high" high String

Donat el següent codi:

int a = 10; int b = 12; int c = b; int d = a; int e = c;

Introdueix el valor de la variable e.

12

Escriu el valor de cada variable, després de que s'executi cada sentència d'aquest programa:

a b c
int a = 0; 0
int b = 0; 0 0
a = 2; 2 0
int c = b; 2 0 0

Quin és el valor d'aquesta variable?

String animal = "tigre";
"animal" "String" animal tigre

L'operador d'assignació en Java és:

<- = := ->

Selecciona les afirmacions correctes sobre les variables.

Una variable té un tipus específic El tipus determina el nom d'una variable No es pot assignar un valor a una variable Es pot llegir el valor d'una variable

Quantes variables s'han declarat al següent codi?

int i = 0, j = 0, k = 0; String s = "s", str = "str"; 5

Selecciona les declaracions vàlides

float aFloat = "23.75f"; String mFloat = "98.7"; int cFloat = 44.3; String kFloat = float; char dFloat = '.'; String tFloat = "float";

El següent codi:

boolean turnedOn = true; turnedOn = false; String turnedOff = turnedOn; System.out.println(turnedOff);
Imprimeix false Imprimeix true S'executa però dona un error No es pot executar

Resol aquests problemes:

Tipus correctes

Valors correctes

Noms correctes

Anomenar variables

Per què el nom és important?

Com ja saps, cada variable té un nom que l'identifica de forma única respecte a les altres variables. Donar un bon nom a una variable potser no és tan simple com sembla. Els programadors amb experiència posen molt de compte en posar els noms per a fer els seus programes més fàcils de comprendre. És molt important perquè els programadors dediquen molt de temps a llegir i comprendre programes escrits per altres programadors. Si les variables tenen noms dolents, inclús el teu propi codi et semblarà poc clar en uns pocs mesos.

Sempre tracta de ser descriptiu i concís al posar nom a les variables. A la llarga ho agrairàs.

A més a més, per a posar noms has de seguir les regles i les convencions.

Regles per a anomenar variables

Les regles de Java per als noms de variables són:

En base a aquestes regles, pots concloure que els espais en blanc no estan permesos en el nom d'una variable.

Si trenques alguna d'aquestes regles el teu programa no funcionarà

Aquí tens alguns exemples de noms vàlids:

numero, $ident, bigValue, _val, abc, k

Aquests són invàlids:

@ab, 1c, !ab, class

Convencions per a anomenar variables

També hi ha una sèrie de convencions per a anomenar variables en Java:

Aquestes convencions són opcionals, tot i que es recomana seguir-les. Com hem dit al principi, aquestes convencions faran el teu programa més legible per a tu i per als altres programadors Java.

Vols declarar una variable anomenada int.

Determina si el nom es vàlid o no (i per què?). Un nom és valid si el programa funcionarà.

Es nom és vàlid El nom no és vàlid perquè no té sentit (què és int?) El nom no és vàlid perquè comença per una lletra El nom no és vàlid perquè és una paraula-clau

Selecciona els noms de variable vàlids, és a dir, que el programa funcionarà.

1poma numero1 boolean _var

Recordes les convencions per anomenar variables? Fes que la variable ALTURA@CACTUS no solament sigui sintàcticament correcta, sinò que també compleixi les recomanacions.

alturaCactus

Quin és el millor nom per una variable d'acord amb les convencions?

_uha userHomeAdress userhomeaddress user_home_address UserHomeAddress

Escanejar l'entrada

L'entrada estàndard és un flux de dades que van cap al programa. Està suportada pel sistema operatiu. Per defecte, l'entrada estàndard obté les dades del teclat, tot i que és possible redirigir-la per a obtenir les dades d'un fitxer.

De fet, no tots els programes utilitzen l'entrada estàndard. Però nosaltres l'utilitzarem molt sovint per a demanar dades als usuaris per teclat, o per a obtenir les dades dels casos de prova en els exercicis.

La forma típica en que resoldrem problemes és aquesta:

  1. Llegir dades de l'entrada estàndard (System.in)

  2. Processar les dades per a obtenir un resultat

  3. Imprimir el resultat a la sortida estàndard (System.out)

Aquest tipus de problemes de programació es poden provar fàcilment amb diferents formats de dades d'entrada, i per aquest motiu, els utilitzarem molt.

Llegir dades amb un scanner

La forma més simple d'obtenir dades de l'entrada estàndard és utilitzar la classe Scanner. Permet als programes llegir valors de diferents tipus (strings, números, etc.) de l'entrada estàndard.

Per a utilitzar la classe Scanner s'ha d'afegir aquesta sentència d'importació al principi del fitxer de codi:

import java.util.Scanner;

Després s'ha d'afegir aquesta construcció a dintre del mètode main:

Scanner scanner = new Scanner(System.in);

En aquesta línia hem creat un objecte de la classe Scanner, que ens permet utilitzar els seus mètodes. Aprendrem més sobre classes i objectes més endavant. System.in indica que es llegirà el flux de dades de l'entrada estàndard (habitualment, el teclat). De moment, no és necessari que comprenguis aquesta línia, solament escriu-la exactament així.

Anem a escriure el primer programa que llegeix dades del teclat:

Prova a escriure i executar aquest programa a l'IntelliJ.

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("Hola, com et dius?"); String nom = scanner.nextLine(); System.out.print("Hola "); System.out.print(nom); System.out.println("!"); } }

Quan l'executem, veurem el següent (en verd es mostra l'entrada introduïda per teclat):

Hola, com et dius? Josep Ramon Hola Josep Ramon!

Veiem pas a pas, l'execució del programa:

Mètodes de la classe Scanner

Hi ha diversos mètodes a la classe Scanner que ens permeten llegir diferents tipus de dades de l'entrada estàndard. En aquesta taula tens un resum dels mètodes que més utilitzarem en aquest curs:

MètodeTipusUtilitat
nextInt()intllegeix un número enter
nextFloat()floatllegeix un número decimal
nextBoolean()booleanllegeix un valor booleà
next()Stringllegeix una paraula
nextLine()Stringllegeix fins al final de línia

Quan llegim dades utilitzant aquests mètodes hem d'utilitzar les variables del tipus adequat per a guardar la dada que es llegeix. Per exemple:

import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner scanner = new Scanner(System.in); int quantitat = scanner.nextInt(); float preu = scanner.nextFloat(); boolean pagat = scanner.nextBoolean(); String codi = scanner.next(); String nom = scanner.nextLine(); System.out.println(quantitat); System.out.println(preu); System.out.println(pagat); System.out.println(codi); System.out.println(nom); } } 5 1,99 true PR101 Galetes Maria 5 1.99 true PR101 Galetes Maria

Observa que el preu introduït per teclat s'ha escrit utilitzant una coma , en lloc d'un punt . per a separar les xifres decimals (1,99 en lloc de 1.99). Això es degut a que l'Scanner utilitza l'idioma del Sistema Operatiu per al format d'entrada, i en castellà/català els decimals es separen amb una coma ,. Si tinguèssim el Sistema Operatiu configurat en anglès, caldria haver introduït el número decimal utlitzant un punt.

Es pot forçar a l'Scanner a utilitzar l'idioma anglès per al format de dades d'entrada, és a dir, a utilitzar el punt en els decimals. Ho podem fer amb el mètode setLocale(), just després de crear l'scanner, així:

Scanner scanner = new Scanner(System.in); scanner.useLocale(Locale.US); // usar el format angles

Per contra, els mètodes print() i println() sempre imprimeixen separant els decimals amb un punt.

Hem vist que cal utilitzar el tipus de variable adequat al mètode que utilitzem per a llegir. Si no utilitzem el tipus adequat, el programa no s'executarà. Per exemple, no podem utilitzar una variable de tipus String per a guardar un valor llegit amb nextInt():

String a = scanner.nextInt(); // error, cal utlitzar el tipus int

Per sort, l'IDE ens ajuda a detectar i solucionar aquests errors, indicant en subratllat vermell l'error i proporcionant ajuda sobre com solucionar-lo:

InputMismatchException

Una altre error que pot ocòrrer és que l'usuari no introdueixi una dada que correspongui amb el tipus que s'ha de llegir. En aquest cas, el programa donarà una excepció i s'aturarà inesperadament.

Per exemple, el següent programa tracta de llegir un enter del teclat, però l'usuari introdueix un text (holaaa). L'execució del programa s'abortarà amb una excepció de tipus InputMismatchException:

System.out.println("Introdueix un número:"); int numero = scanner.nextInt(); Introdueix un número: holaaa Exception in thread "main" java.util.InputMismatchException at java.base/java.util.Scanner.throwFor(Scanner.java:939) at java.base/java.util.Scanner.next(Scanner.java:1594) at java.base/java.util.Scanner.nextInt(Scanner.java:2258)

Més endavant veurem com prevenir aquestes situacions, i fer el nostre programa resistent a qualsevol entrada que introdueixi l'usuari.

Consumir dades de l'entrada

Les crides als mètodes de lectura de l'scanner van consumint dades de l'entrada sempre que hi hagi, i si no hi han dades esperaran fins que hi hagin.

Vegem-ho amb un exemple. Aquest programa llegeix dos números de l'entrada:

System.out.println("Introdueix el primer número:") int a = scanner.nextInt(); System.out.println("Introdueix el segon número:") int b = scanner.nextInt(); System.out.println("Els números introduïts són:") System.out.println(a); System.out.println(b);

Quan executem el programa, la primera crida a nextInt() 2, quedarà esperant a que l'usuari introdueixi un número. Si l'usuari introdueix un únic número, aquest serà consumit de l'entrada i assignat a la variable a. Quan es fa la segona crida a nextInt() 4, el programa tornarà a esperar a que s'introdueixi un altre número.

Introdueix el primer número: 1234 Introdueix el segon número: 6789 Els números introduïts són: 1234 6789

Però, si a la primera crida a nextInt() 2, l'usuari introdueix dos números, el primer d'ells serà consumit per l'scanner i assignat a la variable a, i el segon número quedarà pendent per consumir. Així, a la segona crida a nextInt() 4, l'scanner no esperarà a que s'introdueixi un altre número, sinò que consumirà el número que havia quedat per consumir i quedarà assignat a la variable b sense esperar a que s'introdueixi un altre número.

Introdueix el primer número: 1234 6789 // introdueix dos numeros Introdueix el segon número: // consumeix el segon número Els números introduïts són: 1234 6789

Hi ha situacions en què és una mica enrevesada la lectura de dades. Cal tenir en compte la posició del cursor i la forma en que llegeixen les dades els mètodes.

El primer a tenir en compte és que tots els mètodes, excepte el nextLine(), descarten qualsevol espai-en-blanc o salt-de-línia que troben al flux de dades de l'entrada, fins que troben una dada per a llegir. Per contra, nextLine(), llegirà tots els caracters (incloent espais-en-blanc) fins que trobi un salt-de-línia (que descartarà).

Vejem els comportaments d'aquests mètodes amb varis exemples. Al flux de dades d'entrada indicarem els espais-en-blanc amb el símbol i els salts-de-línia amb el símbol .

Fes coincidir els mètodes de la classe Scanner amb el tipus de valor que llegeixen.

nextInt()int nextBoolean()boolean nextFloat()float next()String

Invoquem el mètode next() i introduïm el número 9 a l'entrada estàndard, quin tipus de dada serà?

String char int float

Hello you

Cada paraula a una línia

Contractar un xef

Carta formal

Arxius de codi font