Εισαγωγή στην Java - κεφ. 4

...ασύγχρονα μαθήματα γλώσσας Java

Εισαγωγή στην Java - κεφ. 4

Δημοσίευσηαπό alkismavridis » 28 Απρ 2012, 16:22

Προηγούμενο: Βασικοί τύποι δεδομένων
Επόμενο: Δομές Ελέγχου και Επανάληψης

Τελεστές


Στόχος αυτού του κεφαλαίου είναι να μάθετε πως να χρησιμοποιείτε τους τελεστές στην Java.
Πάρτε βαθιά ανάσα γιατί θα πούμε πολλάαα πράγματα!


Οι τελεστές είναι σύμβολα (αποτελούμενα από ένα ή περισσότερους χαρακτήρες) που δρώντας σε βασικούς τύπους κάνουν μία ορισμένη δουλειά. Στο προηγούμενο κεφάλαιο είδαμε τους τελεστές πρόσθεσης, αφαίρεσης και πολλαπλασιασμού (+ - και *).

Αυτοί ανήκουν στην κατηγορία των αριθμητικών τελεστών, μιας και δίνουν ως αποτέλεσμα έναν αριθμό.
Επίσης λέγονται δυαδικοί γιατί για να δουλέψουν χρειάζονται δύο τιμές (μία δεξιά και μία αριστερά τους).
Όπως θα δούμε στη συνέχεια υπάρχουν και τελεστές που δεν επιστρέφουν αριθμούς αλλά λογικές τιμές. Επίσης υπάρχουν κάποιοι που για να δουλέψουν χρειάζονται μόνο μία τιμή, και όχι δύο. Αυτούς τους λέμε εναδικούς

Ας αρχίσουμε λοιπόν!


1. Αριθμητικοί τελεστές:
Όσοι δίνουν σαν αποτέλεσμα (επιστρέφουν) αριθμό.
Είναι οι εξής:

Δυαδικοί αριθμητικοί τελεστές
+ κάνει πρόσθεση.
- αφαίρεση
* πολλαπλασιασμό
/ διαίρεση. Θυμηθείτε ότι η διαίρεση με το μηδέν απαγορεύεται. Το πρόγραμμα θα κρασάρει σε αυτή την περίπτωση!
% υπόλοιπο διαίρεσης

Οι τελεστές αυτοί μπορούν να λειτουργήσουν και με μεταβλητές, και με αριθμούς. Μπορούν να εμφανίζονται μέσα σε εντολές και εκφράσεις!

:!:Τελεστής ύψωσης σε δύναμη, σε αντίθεση με άλλες γλώσσες όπως η Fortran δεν υπάρχει, υπάρχει όμως μία συνάρτηση, η Math.pow(...) που κάνει τη δουλειά. Λεπτομέρειες σε επόμενα κεφάλαια.

Εναδικοί αριθμητικοί τελεστές
(μπορούν να μπαίνουν πριν, ή μετά την μεταβλητή)
++ προσθέτει 1
-- αφαιρεί 1

Ας πειραματιστούμε με το παρακάτω πρόγραμμα:
Θα δούμε κάποια νέα στοιχεία: τη μέθοδο println() και μία «περίεργη» χρήση του τελεστή + στα String
Μορφοποιημένος Κώδικας: Επιλογή όλων
//Αρχείο OperatorTest.java
public class OperatorTest {
public static void main(String[] args) {
int a=3, b=6, x;
x=3*5; //το x είναι 15
System.out.println(x); //Η println(...) είναι μία μέθοδος που λειτουργεί όπως η print(...), και αλλάζει σειρά στο τέλος.
//Σας συνιστώ όμως αν θέλετε να τυπώνετε πολλές τιμές να μην την χρησιμοποιείτε γιατί είναι πιο αργή από την print(...)
x=a*11; //το x είναι 33
System.out.println(x);
x=a+b; //το x είναι 9
System.out.println(x);
x++; //το x είναι 10
System.out.println(x);
++x; //το x είναι 11 //Υπάρχει μία μικρή διαφορά μεταξύ ++x; και x++; !! Κοιαξτε τις τελευταίες γραμμές αυτού τοι κώδικα..
System.out.println(x);
x=a-b; //το x είναι -3
System.out.println(x);
x--; //το x είναι -4
System.out.println(x);
x=a*b; //το x είναι 18
System.out.println(x);
x=b/a; //το x είναι 2
System.out.println(x);
x=b%a; //το x είναι 0, γιατί η διαίρεση 3/6 είναι ακριβής
System.out.println(x + "\n\nΤώρα θα δούμε τη διαφορά μεταξύ x++ και ++x");

/*Προσέξτε ότι έχω γράψει: αριθμός + String!! Ο τελεστής + δουλεύει και με String!
Η δουλειά του είναι να ενώνει δύο Strings. Δρά από αριστερά προς τα δεξιά, και μετατρέπει σε κείμενο ό,τι βρεί!
Εδώ αρχικά βρίσκει το x. Το μετατρέπει σε κείμενο, το ενώνει με το String που ακολουθεί.
Το \n\n μη σας μπερδεύει! Είναι απλώς δύο φορές το \n.*/

x=10;
System.out.println("\nΤο x είναι 10\nΕκτελώ την x++: "+ x++); //Αυτή η εντολή πρώτα τυπώνει το i και μετά του προθέτει 1
System.out.println("Δείτε το χ: "+x);
x=10;
System.out.println("\nΤο x είναι πάλι 10\nΕκτελώ την ++x: "+ ++x); //Αυτή η εντολή πρώτα προσέτει 1 στο i και μετά το τυπώνει
System.out.println("Δείτε το χ: "+x);
System.out.print("\n\nΚαταλαβαίνετε τώρα τη διαφορά μεταξύ x++; και ++x; ??\n");
}//MAIN
}//CLASS


Επίσης υπάρχει η εξής συντομογραφία: Όταν ο τελεστής = συνοδεύεται έπεται ένός από τους {+ / * - %} και ακολουθείται από μία τιμή, κάνει την αντίστοιχη πράξη στην μεταβλητή! πχ:

Μορφοποιημένος Κώδικας: Επιλογή όλων
double k=5;
k+=3; //Είναι ίδιο με το k=k+3;
k-=2; //Είναι ίδιο με το k=k-2;
k*=1.5; //Είναι ίδιο με το k=k*1.5;
k/=37; //Είναι ίδιο με το k=k/7;
k%=4; //Είναι ίδιο με το k=k%4; Μην φοβηθείτε να εφαρμόσετε τον τελεστή % σε δεκαδικούς αριθμούς. Έχουν και αυτοί υπόλοιπο διαίρεσης!



Σημαντικό!!
Πρέπει να έχουμε κατά νου τι τύπο δεδομένων επιστρέφουν οι παραπάνω τελεστές. Δηλαδή αν προσθέσω δύο ακαιρέους, το αποτέλεσμα τι τύπο έχει;
Η απάντηση είναι ότι οι αριθμητικοί τελεστές όταν δρουν μεταξύ δύο ίδιων τύπων επιστρέφουν και πάλι αυτόν.
Συμβολικά λοιπόν γράφουμε:
int + int = int
byte * byte = byte
long % long = long κ.τ.λ.
Τονίζω το συμβολικά! Μην γράψετε τα παραπάνω σε κανένα πρόγραμμα, δε θα δουλέψει!

Οι αριθμητικοί τελεστές όμως μπορούν να δράσουν και μεταξύ δύο διαφορετικών τύπων! Πχ μπορούμε να προσθέσουμε ένα int με ένα long. Το αποτέλεσμα όμως τι θα είναι; int ή long; ή μήπως κάτι άλλο;
Η απάντηση είναι ότι όταν εφαρμόζουμε αριθμητικούς τελεστές σε διαφορετικά δεδομένα, κερδίζει... το δυνατότερο!
Αυτό σημαίνει ότι για ακέραιους τύπους το αποτέλεσμα θα είναι αυτό με το μεγαλύτερο μέγεθος. Άρα συμβολικά:
int + long = long
byte - int = int κτλ
με την ίδια λογική: float + double = double

Όταν τώρα κάνουμε πράξεις μεταξύ ακεραίων και δεκαδικών αριθμών, κερδίζει ο δεκαδικός:
double + int = double

Τα παραπάνω ίσως να ακούγονται πολύ λογικά, υπάρχει όμως μία παγίδα.
Κατα τα παραπάνω, η διαίρεση δύο ακεραίων είναι ακέραιος: int / int = int
Ναι όμως μαθηματικά η διαίρεση δύο ακεραίων δεν είναι κατ ανάγκη ακέραιος! πχ 7/2 = 3.5
Τι θα επιστρέψει το πρόγραμμα σε μία τέτοια πράξη;
Η απάντηση είναι ότι όταν στη Java (και στις περισσότερες γλώσσες) γίνεται διαίρεση δύο ακεραίων, το όποιο δεκαδικό μέρος θα προέκυπτε μαθηματικά... κόβεται!
Άρα η πράξη
7 / 2 θα δώσει αποτέλεσμα 3

Η διαίρεση ακαιρέων δε δίνει πάντα το μαθηματικά αναμενόμενο αποτέλεσμα!



Δοκιμάστε το παρακάτω πρόγραμμα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
//Αρχείο DivTest.java
public class DivTest {
public static void main(String[] args) {
int i=7/2; //Κατά την ανάθεση, όπως και σε κάθε εντολή, μπορούμε άνετα να χρησιμοποιήσουμε πράξεις αντί για απ' ευθείας νούμερα!
System.out.print(i); // Δείξε μας το i
System.out.print("\n");
}//MAIN
}//CLASS


Πειραματιστείτε με τα παραπάνω, θα σας βοηθήσει να κατανοήσετε πως λειτουργούν οι αριθμητικοί τελεστές! Μη διστάσετε, αντί για int να χρησιμοποιήσετε άλλους τύπους δεδομένων!

Αριθμιτικές εκφράσεις
Τέλος πολύ σημαντικό είναι ότι, καθώς κάνουμε πράξεις με τους αριθμητικούς τελεστές δε χρησιμοποιούμε μόνο μεταβλητές, αλλά και σταθερές ποσότητες, δηλαδή αριθμιτικές εκφράσεις.
Όταν γράφουμε λοιπόν
int i = 3, j = 7/2*i;
εχει σημασία πως ο compiler βλέπει αυτό το '7' και το '2'. Γιατί αν υποθέσουμε ότι τα βλέπει ως int, τότε εκτελώντας τις πράξεις από αριστερά προς τα δεξιά θα έχουμε:
Μορφοποιημένος Κώδικας: Επιλογή όλων
j = 7/2*3;
j = 3 * 3; //Αφού 7/2 κάνει 3 μιας και το δεκαδικό μέρος .5 θα κοπεί!
j = 9;


Ενώ αν τους δει ως double το αποτέλεσμα θα είναι
Μορφοποιημένος Κώδικας: Επιλογή όλων
j = 7/2*3;
j = 3.5 * 3; //double * int = double
j = 10.5;
j=10; // Αφού το δεκαδικό μέρος θα κοπεί κατά την ανάθεση του 10.5 στον ακαίρεο j


Καταλαβαίνουμε ότι το θέμα έχει τη σημασία του!
Για να χειριστούμε τέτοιες... παρεξηγήσεις υπάρχει ένας μηχανισμός που λέει στον compiler πως να δει τους αριθμούς που του γράφουμε.
Αυτός είναι ο εξής:
1) Aριθμοί χωρίς δεκαδικό μέρος είναι int. Αν ακολουθούνται από το γράμμα l (πχ 200l) είναι long.
2) Αριθμοί με δεκαδικό μέρος είναι double. Αν ακολοθούνται από το γράμμα f (πχ 3.6f) είναι float.
Εδώ να πούμε ότι αν θέλουμε να γράψουμε ένα ακέραιο σε μορφή δεκαδικού, απλώς βάζουμε τελεία στο τέλος: 10. Είναι το ίδιο με το να γράψουμε 10.0

3) Αν ακολουθούνται από το γράμμα e και ένα αριθμό δηλώνουν την εκθετική γραφή. πχ το 1.2e2 σημαίνει 120 (double)

Έτσι λοιπόν ενώ η έκφραση 1/7*7 (εκτελόντας από αριστερά προς τα δεξιά μία-μία τις πράξεις) θα δώσει 0 (int), η 1./7*7 θα δώσει 1. (double, ο οποίος μπορεί κάλλιστα να ανατεθεί σε κάποιον int)



2. Λογικοί Τελεστές
Είναι τελεστές που δίνουν σαν αποτέλεσμα λογικές τιμές, true ή false... και είναι πολύ χρήσιμοι.

Υπάρχουν δυαδικοί λογικοί τελεστές, και ένας εναδικός: το θαυμαστικό !

Ας αρχίσουμε από αυτόν! ο τελεστής ! δρα πάνω σε μια boolean τιμή (τον γράφουμε πριν από την τιμή) και απλώς την αντιστρέφει. Δηλαδή κάνει την true false και την false true.

Μορφοποιημένος Κώδικας: Επιλογή όλων
boolean b = true;
b = !b; //Τώρα η b έγινε false
b = !b; //Τώρα ξανάγινε true...

b = !true; //φυσικά όπως όλοι οι τελεστές, ο ! μπορεί να δράσει και σε μεταβλητές όπως η b, αλλά και σε σταθερές όπως η true.


Δυαδικοί λογικοί τελεστές που δουλεύουν με όλα
== έλεγχος ισότητας
!= έλεγχος μη ισότητας
Ο τελεστής == ελέγχει αν δύο τιμές είναι ίσες. Δρώντας μεταξύ δύο αριθμών θα επιστρέψει true αν οι αριθμοί είναι μαθηματικά ίσοι, false διαφορετικά.
Με την ίδια λογική, δρώντας σε δύο boolean θα μας πει αν είναι ίδιες ή όχι. Μπορεί να δράσει και σε char, ακόμα και (όπως θα δούμε αργότερα)σε αντικείμενα!
Ο τελεστής != λειτουργεί ακριβώς με τα ίδια κριτήρια, κάνοντας την αντίθετη δουλειά: επιστρέφει true αν οι τιμές δεν είναι ίσες, false αν είναι.

Δυαδικοί που δουλεύουν με αριθμούς
> έλεγχος μεγαλύτερου
< έλεγχος μικρότερου
>= έλεγχος μεγαλύτερου ή ίσου
<= έλεγχος μικρότερου ή ίσου

Βάζουμε δύο αριθμούς (οποιουδήποτε ακέραιου ή δεκαδικού βασικού τύπου). Έναν δεξιά και έναν αριστερά του τελεστή!
Το αποτέλεσμα είναι true αν η αντίστοιχη μαθηματική σχέση είναι αληθής, false σε διαφορετική περίπτωση!

Παραδείγματα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
//Αρχείο Boolean1.java
public class Boolean1 {
public static void main(String[] args) {
boolean b;
int i=6, j=6, k=8;
double d = 7.7;

b = 5<4;
System.out.print("5<4 : "+b+"\n");

b = 5<i;
System.out.print("5<6 : "+b+"\n");

b = d>i;
System.out.print("7.7>6 : "+b+"\n");

b = i<j;
System.out.print("6<6 : "+b+"\n");

b = i<=j;
System.out.print("6<=6 : "+b+"\n");

b = i<=j-1;
System.out.print("6<=5 : "+b+"\n");

b = i==j;
System.out.print("6==6 : "+b+"\n");

b = i!=j;
System.out.print("6!=6 : "+b+"\n");
}//main
}//class



Δυαδικοί λογικοί τελεστές που δουλεύουν με boolean
Θα λέγαμε ότι είναι πράξεις μεταξύ boolean.. Αυτοί είναι οι
&& Λογικό και
|| λογικό ή (συνήθως γράφεται κρατώντας Shift και πατώντας το πλήκτρο πάνω από το Enter!)

Οι βασικές τους ιδιότητες είναι οι εξής:
Ο && επιστρέφει true άν και δεξιάτου και αριστερά του υπάρχει true. Άν ένα από τα δύο είναι false επιστρέφει false.
Ο || επιστρέφει true άν ένα από τα δύο (δεξιά του ή αριστερά του) είναι true. Αν είναι και τα δύο false, επιστρέφει false.

Παραδείγματα
Μορφοποιημένος Κώδικας: Επιλογή όλων
boolean b1, b2;
b1 = true || true; // b1 = true
b1 = true || false; // b1 = true
b1 = false || true; // b1 = true
b1 = false || false; // b1 = false

b1 = true && true; //b1 = true
b1 = true && false; //b1 = false
b1 = false && true; //b1 = false
b1 = false && false; //b1 = false

b1 = false;
b2 = b1 || 1>0; // b2 = true
b2 = b1 && b2; // b2 = false
b2 = !b1 && !b2; // b2 = true


Σημαντικό!
Αν ο compiler κατά την εκτέλεση του && δει ότι η πρώτη (αριστερή) boolean είναι false, δε θα κοιτάξει καν τη δεύτερη και θα επιστρέψει false.
Ομοίως για την εκτέλεση του ||, θα επιστρέψει true χωρίς να κοιτάξει την δεύτερη αν βρει την πρώτη true!


Τέλος υπάρχει και ο τελεστής instanceof για τον οποίο θα μιλήσουμε όταν ασχοληθούμε με αντικείμενα.
Όλοι οι τελεστές της Java, και αυτοί που αναφέρθηκαν, αλλά και κάποιοι πιο εξειδικευμένοι υπάρχουν εδώ.


Προτεραιότητα τελεστών και παρενθέσεις
Στους τελεστές υπάρχει μία ιεραρχία ως προς το ποιοι εκτελούνται πρώτα και ποιοι αργότερα.
Όσοι από τους τελεστές βρίσκονται στις πιο πάνω σειρές στην παρακάτω λίστα θα εκτελεστούν πιο πριν από αυτούς στις πιο κάτω:

1) exp++ exp--
2) ++exp --exp !
3) * / %
4) + -
5) < > <= >= instanceof
6) == !=
7) &&
8) ||
9)= += -= *= /= %=

Για αυτούς που είναι στην ίδια σειρά ισχύει ο κανόνας ότι η εκτέλεση αρχίζει από αριστερά προς τα δεξιά. Μόνο για τους τελεστές της σειράς 9 ισχύει το αντίθετο: η εκτέλεση αρχίζει από δεξιά προς τα αριστερά.

Πχ στην έκφραση
int i = 4+10/2;
Θα εκτελεστεί πρώτα η διαίρεση και μετά η πρόσθεση άρα το αποτέλεσμα είναι το 9.

Αν θέλουμε να αλλάξουμε την προτεραιότητα των πράξεων χρησιμοποιούμε παρενθέσεις Οι παρενθέσεις έχουν την απόλυτη προτεραιότητα έναντι κάθε τι που συμβαίνει έξω από αυτές.
Δηλαδή στην παραπάνω περίπτωση, αν βάλουμε παρενθέσεις κάπως έτσι:
int i = (4+10)/2;
το αποτέλεσμα θα είναι το 7, γιατί η πρόσθεση θα εκτελεστεί πρώτα λόγω της παρένθεσης.

Προηγούμενο: Βασικοί τύποι δεδομένων
Επόμενο: Προσεχώς

Creative Commons License
Η εργασία υπάγεται στην άδεια Creative Commons Αναφορά-Παρόμοια διανομή 3.0 Ελλάδα
Γνώσεις ⇛ Linux: Μέτριο┃ Προγραμματισμός: Java, Assembly, Fortran, μαθαίνω C/X11┃ Αγγλικά: Μέτρια
Λειτουργικό σε Η/Υ ϰ μοντέλο: Ubuntu 14.04 64-bit ┃ Τρόπος εγκατάστασης: Live USB
Προδιαγραφές ⇛ Desktop: Intel i5 2320 3.00GHz.┃ MotherBoard: Asus p8h61 -m pro
Προδιαγραφές ⇛ RAM: 4GB ┃ Τροφοδοτικό Corsair CX430

GPU: Intel 2nd Generation Core Processor Family Integrated Graphics Controller [8086:0102] {i915}
5 eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller [10ec:8168] (rev 06) ⋮ wlan0: 0b05:1723 ASUS WL-167G v2 802.11g Adapter [Ralink RT2571W]
Οθόνη Schaub Lorenz (Tv)
alkismavridis
punkTUX
punkTUX
 
Δημοσιεύσεις: 273
Εγγραφή: 18 Μαρ 2009, 18:46
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 4

Δημοσίευσηαπό Vegeta » 30 Δεκ 2014, 08:24

2-3 επισημάνσεις:

στο πρώτο κομμάτι κώδικα που δίνεις:
x=b%a; //το x είναι 0, γιατί η διαίρεση 6/3 είναι ακριβής
System.out.println("\nΤο x είναι 10\nΕκτελώ την x++: "+ x++); //Αυτή η εντολή πρώτα τυπώνει το x και μετά του προσθέτει 1
System.out.println("\nΤο x είναι πάλι 10\nΕκτελώ την ++x: "+ ++x); //Αυτή η εντολή πρώτα προσθέτει 1 στο x και μετά το τυπώνει

η γνώμη μου είναι, στα δύο παραπάνω, η αρχική τιμή του x να διαβάζεται από την μεταβλητή και να εμφανίζεται. δηλαδή κάτι σαν αυτό:
System.out.println("\nΤο x είναι "+ x +"\nΕκτελώ την x++: "+ x++); //Αυτή η εντολή πρώτα τυπώνει το x και μετά του προσθέτει 1

σχετικά με τον τελεστή / και το "Η διαίρεση ακαιρέων δε δίνει πάντα το μαθηματικά αναμενόμενο αποτέλεσμα!" :
καλύτερα απλά να πεις: ... "δίνει το ακέραιο πηλίκο"
Πιστεύω ότι στο συγκεκριμένο σημείο ήταν η καταλληλότερη στιγμή να μιλήσεις για casting (περίπου το κάνεις ;) )

Σημαντικό!
Αν ο compiler κατά την εκτέλεση του && δει ότι η πρώτη (αριστερή) boolean είναι false, δε θα κοιτάξει καν τη δεύτερη και θα επιστρέψει false.
Ομοίως για την εκτέλεση του ||, θα επιστρέψει true χωρίς να κοιτάξει την δεύτερη αν βρει την πρώτη true!

μου αρέσει που πέρα από το πως λειτουργεί η γλώσσα, δίνεις και την εικόνα του complier, δίνοντας στο κείμενο μία "πιο επιστημονική" χροιά! :clap:
Linux: Καλά | Προγραμματισμός: Καλά | Αγγικά: Καλά
Asus TUF Gaming A15 FA506IV-HN216T (Ryzen 9-4900H/16GB/512GB/GeForce RTX 2060/FHD/W10)
Ubuntu 20.04.1 LTS
Άβαταρ μέλους
Vegeta
babeTUX
babeTUX
 
Δημοσιεύσεις: 83
Εγγραφή: 25 Μαρ 2010, 13:49
Εκτύπωση


  • ΣΧΕΤΙΚΑ ΘΕΜΑΤΑ
    ΑΠΑΝΤΗΣΕΙΣ
    ΠΡΟΒΟΛΕΣ
    ΣΥΓΓΡΑΦΕΑΣ

Επιστροφή στο Μαθήματα Java