Phép toán trong Java

Trong bài này của seri hướng dẫn lập trình Java Core, chúng ta sẽ nói về các biểu thức.

Biểu thức được xây dựng từ các toán hạng và toán tử. Các toán tử của một biểu thức chỉ ra phép toán (+ – * /,…) nào sẽ áp dụng cho các toán hạng. Thứ tự thực hiện phép toán trong một biểu thức được xác định bởi sự ưu tiên và sự kết hợp của các toán tử.

Toán tử là một symbol đặc biệt chỉ ra một quá trình nhất định được thực hiện. Các toán tử trong ngôn ngữ lập trình được lấy từ toán học. Ví dụ: 5+7 – 2*3/8. Trong đó 5, 7, 2, 3, 8 là các toán hạng, còn + – * / là các toán tử.

Một toán tử thường có một hoặc hai toán hạng. Những toán tử làm việc với chỉ một toán tử được gọi là toán tử đơn. Những người làm việc với hai toán hạng được gọi là các toán tử nhị phân. Ngoài ra còn có một toán tử thứ ba: có làm việc với ba toán hạng.

Một số toán tử có thể được sử dụng trong các ngữ cảnh khác nhau. Ví dụ như toán tử + có thể được sử dụng trong các trường hợp khác nhau như: cộng 2 số, nối các chuỗi hoặc chỉ dấu của một số. Chúng ta có thể gọi là chồng toán tử.

Toán tử dấu trong Java

Có 2 toán tử + và -. Chúng được sử dụng để chỉ định dấu của số.

SignOperators.java

package net.vncoding;

public class SignOperators {

    public static void main(String[] args) {
        
        System.out.println(2);
        System.out.println(+2);
        System.out.println(-2);
    }
}

Toán tử + và – được sử dụng để chỉ định dấu của giá trị. Dấu + là để chỉ định giá trị dương. Dấu – chỉ định giá trị âm.

MinusSign.java

package net.vncoding;


public class MinusSign {

    public static void main(String[] args) {
        
        int a = 1;
        
        System.out.println(-a);
        System.out.println(-(-a));    
    }
}

Toán tử – thay đổi dấu của giá trị.

Kết quả:
-1
1

Toán tử gán

Toán tử gán = gán một giá trị cho một biến. Hay nói cách khác, biến lưu trữ giá trị.

int x = 1;

Gán giá trị 1 cho biến x

x = x + 1;

Biến x được cộng với 1. Kết quả x+1 = 2 được gán cho x. Cuối cùng, x = 2.

3 = x;

Câu lệnh này sai cú pháp. Không thể gán biến x cho hằng giá trị 3.

Nối 2 chuỗi

Toán tử + được sử dụng nối 2 chuỗi trong Java.

ConcatenateStrings.java

package net.vncoding;

public class ConcatenateStrings {

    public static void main(String[] args) {
    
        System.out.println("Return " + "of " + "the king.");
        System.out.println("Return".concat(" of").concat(" the king."));
    }
}

Trong ví dụ này, sử dụng 2 cách để nối chuỗi trong Java.

System.out.println("Return " + "of " + "the king.");

Toán tử + được sử dụng để nối 3 chuỗi.

System.out.println("Return".concat(" of").concat(" the king."));

Sử dụng phương thức concat() để nối chuỗi.

Kết quả:
Return of the king.
Return of the king.

Toán tử tăng giảm

Việc tăng/giảm 1 giá trị rất phổ biến trong lập trình. Java sử dụng 2 toán tử ++ để tăng giá trị lên 1 và — để giảm giá trị của biến đi 1.

IncDec.java

package net.vncoding;

public class IncDec {

    public static void main(String[] args) {

        int x = 6;

        x++;
        x++;

        System.out.println(x);

        x--;
        System.out.println(x);
    }
}

Ví dụ trên minh họa sử dụng toán tử ++, —

int x = 6; 
x++;
x++;

Biến x được tăng lên 2 giá trị, x = 8

x--;

Giảm giá trị biến x đi 1 đơn vị, x = 7

Kết quả:
8
7

Toán tử số học

Toán tử Tên
+ Phép cộng
Phép trừ
* Phép nhân
/ Phép chia
% Phép chia lấy phần dư

Arithmetic.java

package net.vncoding;

public class Arithmetic {

    public static void main(String[] args) {
        
        int a = 10;
        int b = 11;
        int c = 12;

        int add = a + b + c;
        int sb = c - a;
        int mult = a * b;
        int div = c / 3;
        int rem = c % a;

        System.out.println(add);
        System.out.println(sb);
        System.out.println(mult);
        System.out.println(div);
        System.out.println(rem);
    }
}

Tất cả các phép toán cộng, trừ, nhân, chia đã quen thuộc với các bạn. Ở đây, chỉ nói thêm toán tử %

int rem = c % a;

Toán tử lấy phần dư của phép chia.

Kết quả:
33
2
110
4
2

Tiếp theo, chúng ta phân biệt phép chia giữa 2 số nguyên và số thập phân.

Division.java

package net.vncoding;

public class Division {

    public static void main(String[] args) {
        
        int c = 5 / 2;
        System.out.println(c);

        double d = 5 / 2.0;
        System.out.println(d);    
    }
}

Phép chia số nguyên và số thập phân có đôi chút khác nhau.

int c = 5 / 2;

Phép chia 2 số nguyên trả về số nguyên là thương số của phép chia.

double d = 5 / 2.0;

Phép chia số thập phân (chỉ cần có tử số hoặc mẫu số là số thập phân), kết quả là về là số thập phân.

Kết quả:
2
2.5

Toán tử boolean

Trong Java, có 3 toán tử boolean.

Toán tử Tên
&& Toán tử logic AND
|| Toán tử logic OR
! Toán tử phủ định NOT

Toán tử boolean còn được gọi là toán tử logic.

BooleanOperators.java

package net.vncoding;

public class BooleanOperators {

    public static void main(String[] args) {

        int x = 3;
        int y = 8;

        System.out.println(x == y);
        System.out.println(y > x);

        if (y > x) {
            
            System.out.println("y is greater than x");
        }
    }
}

Toán tử boolean được sử dụng trong các biểu thức điều kiện.

System.out.println(x == y);
System.out.println(y > x);

Toán tử quan hệ trả về kết quả là true/false

if (y > x) {
    
    System.out.println("y is greater than x");
}

Body của câu lệnh if được thực hiện nếu y lớn hơn x, tức là biểu thức điều kiện (y > x) trả về true.

AndOperator.java

package net.vncoding;

public class AndOperator {

    public static void main(String[] args) {

        boolean a = true && true;
        boolean b = true && false;
        boolean c = false && true;
        boolean d = false && false;

        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
    }
}

Ví dụ minh họa kết quả của toán tử && khi AND 2 giá trị boolean. Kết quả là true khi và chỉ khi cả 2 toán hạng là true.

Kết quả:
true
false
false
false

Tiếp theo, chúng ta xét ví dụ toán tử ||

OrOperator.java

package net.vncoding;

public class OrOperator {

    public static void main(String[] args) {
        
        boolean a = true || true;
        boolean b = true || false;
        boolean c = false || true;
        boolean d = false || false;

        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);    
    }
}

Toán tử || trả về kết quả true khi 1 trong 2 toán hạng có giá trị true.

Kết quả:
true
true
true
false

Tiếp theo, chúng ta xét đến ví dụ toán tử NOT

Negation.java

package net.vncoding;
public class Negation {

    public static void main(String[] args) {
        
        System.out.println(! true);
        System.out.println(! false);
        System.out.println(! (4 < 3));    
    }
}

Kết quả:
false
true
true

Toán tử quan hệ

Toán tử quan hệ được sử dụng để compare 2 giá trị. Toán tử quan hệ trả về true hoặc false.

Toán tử Tên
< Toán tử so sánh nhỏ hơn
<= Toán tử so sánh nhỏ hơn hoặc bằng
> Toán tử so sánh lớn hơn
>= Toán tử so sánh lớn hơn hoặc bằng
== Toán tử so sánh bằng
!= Toán tử so sánh không bằng

Toán tử quan hệ còn được gọi là toán tử so sánh.

Relational.java

package net.vncoding;

public class Relational {

    public static void main(String[] args) {
        
        System.out.println(3 < 4); System.out.println(3 == 4); System.out.println(4 >= 3);
        System.out.println(4 != 3);
    }
}

Kết quả:
true
false
true
true

Toán tử xử lí bit

Số thập phân là tự nhiên đối với con người. Số nhị phân có nguồn gốc từ máy tính. Các ký hiệu nhị phân, bát phân, thập phân hoặc thập lục phân chỉ là ký hiệu của một số. Các toán tử Bitwise làm việc với các bit của một số nhị phân. Các toán tử Bitwise ít khi được sử dụng trong các ngôn ngữ bậc cao hơn như Java.

Toán tử Ý nghĩa
~ Toán tử phủ định bit
^ Toán tử XOR bit
& Toán tử AND bit
| Toán tử OR bit

Toán tử phủ định bit, đảo bit 1 –> 0 và 0 –> 1

System.out.println(~7); // prints -8
System.out.println(~ -8); // prints 7

Toán tử ~ đảo tất cả các bit của 7. Bit đầu tiên quyết định là giá trị âm hay dương. Nếu sử dụng toán tử ~ thêm 1 lần nữa, kết quả quay về giá trị ban đầu là 7.

Toán tử AND bit, các bit lần lượt được AND với nhau. Kết quả là 1 nếu 2 bit cùng là 1.

      00110
   &  00011
   =  00010
System.out.println(6 & 3); // prints 2
System.out.println(3 & 6); // prints 2

Toán tử OR bit, các bit lần lượt được OR với nhau. Kết quả là 1 nếu 1 trong 2 bit có giá trị là 1.

     00110
   | 00011
   = 00111
System.out.println(6 | 3); // prints 7
System.out.println(3 | 6); // prints 7

Toán tử XOR bit, các bit lần lượt được XOR với nhau. Kết quả là là 1 nếu 2 bit có giá trị khác nhau.

      00110
   ^  00011
   =  00101
System.out.println(6 ^ 3); // prints 5
System.out.println(3 ^ 6); // prints 5

Toán tử gán gộp

Toán tử gán gộp là cách viết tắt của 2 toán tử

a = a + 3;
a += 3;

2 dòng lệnh trên là tương đương. Biến a được tăng thêm 3 đơn vị.

Các toán tử gán gộp khác

-=   *=   /=   %=   &=   |=   <<= >>= 

Ví dụ:
CompoundOperators.java

public class CompoundOperators {

    public static void main(String[] args) {
        
        int a = 1;
        a = a + 1;
 
        System.out.println(a); 
        
        a += 5;
        System.out.println(a);    
        
        a *= 3;
        System.out.println(a);    
    }
}

Chúng ta sử dụng toán tử += và *=

int a = 1;
a = a + 1;

Biến a được khởi tạo 1 và được tăng thêm 1. Sau dòng code trên, a = 2

a += 5;

Giá trị a được cộng với 5, a = 2 + 5 = 7

a *= 3;

Giá trị a được nhân với 3, a = 7 * 3 = 21

Kết quả:
2
7
21

Toán tử instanceof

Toán tử instanceof so sánh 1 object với kiểu dữ liệu

InstanceofOperator.java

package net.vncoding;

class Base {}
class Derived extends Base {}

public class InstanceofOperator {

    public static void main(String[] args) {
        
        Base b = new Base();
        Derived d = new Derived();
        
        System.out.println(d instanceof Base);
        System.out.println(b instanceof Derived);
        System.out.println(d instanceof Object);    
    }
}

Trong ví dụ, sử dụng 2 class: 1 base class và 1 class kế thừa từ base class.

System.out.println(d instanceof Base);

Dòng code này kiểm tra biến d có trỏ tới class mà là instance of class Base hay không?. Vì class Derived là lớp kế thừa của class Base. Do vậy, d cũng là instance của class Base.

System.out.println(b instanceof Derived);

Object b không phải là instance của class Derived.

System.out.println(d instanceof Object);

Mọi class đều coi Object như Supper class. Do đó, object d cũng là instance của class Object.

Kết quả:
true
false
true

Toán tử lamda

Java 8 đã giới thiệu toán tử lamda (->)

(parameters) -> expression          
(parameters) -> { statements; }

Đây là cú pháp cơ bản cho một biểu thức lambda trong Java. Biểu thức Lambda cho phép tạo ra mã súc tích hơn trong Java.

Khai báo kiểu tham số là tùy chọn; trình biên dịch có thể suy ra kiểu từ giá trị của tham số. Đối với một tham số duy nhất, dấu ngoặc đơn là tùy chọn; cho nhiều tham số, chúng được yêu cầu. Dấu ngoặc nhọn là tùy chọn nếu chỉ có một câu lệnh trong một biểu thức. Cuối cùng, keyword return là tùy chọn nếu body có một biểu thức để trả về giá trị; dấu ngoặc nhọn được yêu cầu để chỉ ra rằng biểu thức trả về giá trị.

LambdaExpression.java

package net.vncoding;

import java.util.Arrays;

public class LambdaExpression {

    public static void main(String[] args) {
        
        String[] words = { "kind", "massive", "atom", "car", "blue" };
        
        Arrays.sort(words, (String s1, String s2) -> (s1.compareTo(s2)));
        
        System.out.println(Arrays.toString(words));
    }
}

Trong ví dụ này, chúng ta định nghĩa 1 mảng các chuỗi kí tự. Mảng được sắp xếp bằng phương thức Arrays.sort() và biểu thức lamda.

Kết quả:
[atom, blue, car, kind, massive]

Biểu thức Lambda được sử dụng chủ yếu để định nghĩa 1 inline function interface. Ví dụ như: 1 interface với phương thức đơn. Interface là kiểu dữ liệu trừu tượng, được sử dụng để thực thi contract.

LambdaExpression2.java

package net.vncoding;

interface GreetingService {

    void greet(String message);
}

public class LambdaExpression2 {

    public static void main(String[] args) {

        GreetingService gs = (String msg) -> {
            System.out.println(msg);
        };

        gs.greet("Good night");
        gs.greet("Hello there");
    }
}

Trong ví dụ, chúng ta tạo ra 1 Greeting service bằng việc sử dụng biểu thức lamda.

interface GreetingService {

    void greet(String message);
}

Interface GreetingService được tạo, thì tất cả các object implement Interface phải implement phương thức greet().

GreetingService gs = (String msg) -> {
    System.out.println(msg);
};

Chúng ta tạo object implement Interface GreetingService với biểu thức lamda. Đối tượng có phương thức in nội dung ra màn hình console.

gs.greet("Good night");

Gọi phương thức greet().

Kết quả:
Good night
Hello there

Ngoài ra, còn có các Interface khác như: Function, Consumer, hoặc Supplier

LambdaExpression3.java

package net.vncoding;

import java.util.function.Function;

public class LambdaExpression3 {

    public static void main(String[] args) {

        Function<Integer, Integer> square = (Integer x) -> x * x;
        System.out.println(square.apply(5));
    }
}

Trong ví dụ này, sử dụng biểu thức lamda để tính bình phương của số nguyên.

Function<Integer, Integer> square = (Integer x) -> x * x;
System.out.println(square.apply(5)); 

Function là phương thức nhận 1 tham số đầu vào và tạo ra kết quả. Biểu thức lamda tạo ra kết quả là bình phương của số nguyên.

Toán tử ::

Toán tử :: được giới thiệu trong Java 8, được sử dụng để tạo reference tới phương thức.

DoubleColonOperator.java

package net.vncoding;

import java.util.function.Consumer;

public class DoubleColonOperator {
    
    private static void greet(String msg) {
        
        System.out.println(msg);
    }

    public static void main(String[] args) {

        Consumer<String> f = DoubleColonOperator::greet;
        f.accept("Hello there");
    }
}

Trong đoạn code này, chúng ta tạo reference tới phương thức tĩnh với toán tử ::

private static void greet(String msg) {
    
    System.out.println(msg);
}

Phương thức tĩnh in chuỗi ra màn hình console.

Consumer<String> f = DoubleColonOperator::greet;

Consumer là interface mô tả chức năng nhận giá trị đầu vào, không trả về giá trị. Với toán tử ::, chúng ta tạo ra reference tới phương thức greet().

f.accept("Hello there");

Nhận chuỗi đầu vào với phương thức accept()

Độ ưu tiên toán tử trong Java

Độ ưu tiên toán tử nói compiler biết toán tử nào sẽ được thực hiện trước .

Ouput của biểu thức sau đây là 28 hay 40?
3 + 5 * 5
Giống như trong toán học, toán tử nhân (*) có độ ưu tiên cao hơn toán tử cộng. Do đó, kết quả: 28
Để thay đổi thứ tự thực hiện phép toán, chúng ta có thể sử dụng dấu ngoặc ()
(3 + 5)*5 = 40

Dưới đây bảng thứ tự ưu tiên của toán tử trong Java

Toán tử Ý nghĩa Trình tự kết hợp
[] () . Truy cập mảng, gọi phương thức, truy cập đối tượng Trái -> Phải
++ — + – Tăng, giảm, cộng, trừ Phải -> Trái
! ~ (type) new Phủ định, đảo bit, ép kiểu, tạo object Phải -> Trái
* / % Nhân, chia, chia lấy phần dư Trái -> Phải
+ – Cộng, trừ Trái -> Phải
+ Nối 2 chuỗi Trái -> Phải
<< >> >>> Dịch bit Trái -> Phải
< <= > >= Nhỏ, nhỏ hơn hoặc bằng, lớn hơn, lớn hơn hoặc bằng Trái -> Phải
instanceof So sánh Trái -> Phải
== != so sánh bằng, không bằng Trái -> Phải
& AND bit Trái -> Phải
^ XOR bit Trái -> Phải
| OR bit Trái -> Phải
&& AND logic Trái -> Phải
|| OR logic Trái -> Phải
? : Toán tử điều kiện Phải -> Trái
= Toán tử gán Phải -> Trái
+= -= *= /= %= &= Toán tử gán gộp Phải -> Trái
^= |= <<= >>= >>>= Toán tử gán gộp Phải -> Trái

 

– Các toán tử cùng hàng thì cùng mức độ ưu tiên, các toán tử ở dòng trên có mức độ ưu tiên cao hơn dòng dưới.
– Đối với các toán tử cùng mức độ ưu tiên, thì trình tự tính toán có thể từ trái qua phải hoặc từ phải qua trái ( xem ở cột thứ tự kết hợp).
– Nếu không chắc chắn về việc sử dụng thứ tự ưu tiên, thì nên dùng () trong biểu thức.

Precedence.java

package net.vncoding;

public class Precedence {

    public static void main(String[] args) {
        
        System.out.println(3 + 5 * 5);
        System.out.println((3 + 5) * 5);

        System.out.println(! true | true);
        System.out.println(! (true | true));    
    }
}

Kết quả:
28
40
true
false

Associativity.java

package net.vncoding;

public class Associativity {

    public static void main(String[] args) {

        int a, b, c, d;
        a = b = c = d = 0;

        String str = String.format("%d %d %d %d", a, b, c, d);
        System.out.println(str);

        int j = 0;
        j *= 3 + 1;
        System.out.println(j);
    }
}

Kết quả:
0 0 0 0
0

Toán tử (? : )

Toán tử ( ? : ) là toán tử điều kiện. Nó rất thuận tiện trong trường hợp bạn muốn lựa chọn 1 trong 2 giá trị.

cond-exp ? exp1 : exp2

Nếu biểu thức điều kiện là true, giá trị trả về là exp1. Nếu biểu thức điều kiện cond-exp là false, giá trị trả về là exp2.

TernaryOperator.java

package net.vncoding;

public class TernaryOperator {

    public static void main(String[] args) {
        
        int age = 31;

        boolean adult = age >= 18 ? true : false;

        System.out.println(String.format("Adult: %s", adult));    
    }
}

Biểu thức điều kiện (age >=18) là true, biến adult = true.

Kết quả:
Adult: true

Trong bài này, chúng ta đã discuss về biểu thức, toán tử, thứ tự ưu tiên và cách kết hợp toán tử trong Java.

Be the first to comment

Leave a Reply

Your email address will not be published.

*