Cài Đặt Visual Studio Code Lập Trình C/C++

 Cài Đặt Visual Studio Code Lập Trình C++ Dễ Như Ăn Kẹo


Mình đã viết một bài hướng dẫn cài Visual Studio Code để lập trình C++. Nhưng, dường như cách đó gây khó khăn cho các bạn khi thực hiện. Nên hôm nay mình sẽ trình bày một cách khác đơn giản hơn để các bạn có thể thực hiện thành công một cách dễ dàng.

Một số yêu cầu của VSCode:

  • CPU từ 1.6 GHz trở lên
  • RAM từ 1 GB
  • Có Microsoft .NET Framework 4.5.2

Hướng dẫn cài đặt vscode để lập trình C++ trên Windows

1. Tải và cài đặt vscode

Các bạn vào trang chủ vscode link này, chọn phiên bản phù hợp với thiết bị của các bạn và tải về.

Sau khi tài về, tiến hành chạy file cài đặt. Việc cài đặt rất đơn giản, chỉ cần Next – Next – Next là xong.

2. Cài extension C++

Sau khi cài đặt, vscode sẽ có giao diện như thế này:

Các bạn ấn vào Extensions hoặc Ctrl + Shift + X, để mở giao diện như hình dưới.

Tiếp theo các bạn gõ trên thanh tìm kiếm từ khóa “C++”, sau đó chọn extension C/C++ do Microsoft phát hành và ấn Install để cài đặt.

Sau khi quá trình cài đặt hoàn tất bạn hãy tắt VSCode đi (bước này quan trọng nha).

3. Cài đặt môi trường

Cài compile: MinGW

Các bạn vào link này và tải bộ cài MinGW về. Sau đó, các bạn mở file vừa tải về ra:

Install -> Chọn vị trí lưu compile nếu muốn hoặc để mặc định cho ló nhanh :), Continue.

Nhớ vị trí lưu compile, lúc sau sẽ cần dùng đến.

Đợi tool tải dữ liệu xong, Continue.

Đến đây, các bạn mark 2 dòng mingw32-base và mingw32-gcc-g++. Sau đó, Installation -> Apply Changes. Rồi tiếp tục chờ ...

Đến khi tool tải xong các dữ liệu cần thiết thì Close và thoát ra.

Cài đặt môi trường

Mở của số System: Chuột phải vào biểu tượng This PC -> Properties, Windows Settings hiện ra, lướt xuống phần related settings, chọn Advanced system settings. Hoặc vào Windows Search gõ Advanced system settings -> Environment Variables.

Trong mục System variables, chọn Path -> Edit

Chọn New. Tìm đường dẫn chứa thư mục bin của compile, copy, paste vào rồi nhấn OK.

Đường dẫn mặc định là: C:\MinGW\bin

Để kiểm tra đã cài Path thành công hay chưa bạn mở Command Prompt (cmd) và gõ:

g++ --version

Nếu kết quả xuất hiện như hình dưới là bạn đã thành công, nếu không bạn hãy kiểm tra lại nhé.

4. Biên tập và chạy chương trình trên terminal

Chương trình đầu tiên: Hello World.

Mở Vscode lên. Trên thanh công cụ: File -> Open Folder và mở hoặc tạo một thư mục mới (ví dụ Test chẳng hạn), sau đó Select folder.

.

Nhấn vào biểu tượng New File rồi tạo một file mới tên là HelloWorld.cpp và gõ đoạn code huyền thoại sau:

#include <iostream>

using namespace std;

int main()
{
    cout << "Hello World!" << endl;

    return 0;
}

Ctrl + S để lưu lại. Để biên dịch và chạy chương trình bạn vào terminal gõ dòng lệnh:

g++ -g HelloWorld.cpp -o HelloWorld.exe

Hoặc nhấn tổ hợp Ctrl + Shift + B -> C/C++: g++.exe build active file. Hệ thống sẽ biên dịch HelloWorld.cpp và tạo ra file thực thi HelloWorld.exe.

Để chạy chương trình bạn gõ lệnh:

./HelloWorld.exe

Terminal sẽ hiện kết quả như hình dưới:

5. Biên dịch và chạy chương trình trên console

Để chạy chương trình, các bạn nhấn F5 -> C++ (Windows), một file launch.json được tạo ra. Các bạn sửa file lại như sau:

"configurations": [
    {
        //...

        //Sửa lại
        "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
        
        //...
        //Thêm
        "preLaunchTask": "C/C++: g++.exe build active file"
    }
]

Các bạn có thể copy đoạn code sau:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(Windows) Launch",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "console": "externalTerminal",
            "preLaunchTask": "C/C++: g++.exe build active file"
        }
    ]
}

Ctrl + S để lưu, quay trở lại file HelloWord.cpp nhấn F5 một lần nữa. Chương trình đã chạy trên Console.

Lưu ý: Nếu bạn muốn chạy chương trình ngay trong Terminal thì sử lại dòng "console": "externalTerminal", thành "console": "integratedTerminal",.

Kết

Trên đây, mình đã giới thiệu với các bạn về Visual Studio Code và các cài đặt để lập trình C++. Hy vọng với cách này sẽ giúp các bạn thực hiện thành công.

[Tự học tin học văn phòng] Cách dùng hàm MATCH

 




Khi tìm kiếm dữ liệu trên trang tính Excel, bạn thường sử dụng hàm nào? Có lẽ câu trả lời phổ biến nhất là hàm VLOOKUP. 

Giới thiệu hàm MATCH trong Excel

Hàm MATCH trong Excel là hàm tham chiếu có chức năng tìm kiếm một giá trị được xác định trong một phạm vi trang tính và trả về vị trí tương đối của giá trị đó. Điểm đặc biệt khiến hàm MATCH trở nên nổi bật chính là hiệu quả tối ưu khi làm việc với các bảng, các mảng số liệu phức tạp. Hãy bắt đầu khám phá hàm tìm kiếm trong Excel này ngay thôi!

[Tự học tin học văn phòng] Cách kết hợp hàm INDEX và MATCH trong Excel để dò nhiều điều kiện

1Sự khác nhau giữa hàm INDEX + MATCH và hàm VLOOKUP, HLOOKUP

Hàm VLOOKUPHLOOKUP là 2 hàm dò tìm dữ liệu và phổ biến với nhiều người. Tuy nhiên, hàm VLOOKUP, HLOOKUP có giới hạn đó là giá trị trả về phải nằm ở cột bên phải so với giá trị dò tìm với hàm VLOOKUP và nằm ở cột bên dưới với hàm HLOOKUP.

Ở ví dụ bên dưới, ta có thể dùng hàm VLOOKUP và HLOOKUP để dò tìm giá trị cho cột Tên hãng và hàng Tên hãng trong 2 bảng màu vàng từ 2 bảng dữ liệu màu xanh.

Có thể sử dụng hàm VLOOKUP

Nếu thứ tự bảng màu xanh đảo ngược lại, bạn không thể sử dụng hàm VLOOKUP và HLOOKUP nữa.

Không thể sử dụng hàm VLOOKUP và HLOOKUP

Như vậy, nếu bạn cần dò tìm giá trị theo chiều ngược lại, hàm INDEX kết hợp với hàm MATCH sẽ giúp bạn giải quyết vấn đề này.

Ngoài ra, các lợi ích khác khi dùng hàm INDEX kết hợp với hàm MATCH so với hàm VLOOKUP, HLOOKUP đó là:

  • Chèn hay xóa cột một cách an toàn: Vì hàm MATCH giúp xác định rõ cột chứa giá trị cần tìm một cách trực tiếp 
  • Không đặt giới hạn cho kích thước dữ liệu cần tìm: Với hàm VLOOKUP và HLOOKUP thì giá trị cần tìm kiếm không được vượt quá 255 ký tự. 
  • Tốc độ xử lý nhanh hơn: Việc sử dụng hàm INDEX kết hợp hàm MATCH sẽ tăng tốc độ xử lý nhanh hơn từ 10% đến 15% trong bảng tính lớn.

Xem thêm: Hàm SUMIF

2Hàm INDEX và hàm MATCH

Công thức hàm INDEX

Hàm INDEX trả về giá trị theo vị trí của hàng và cột trong một bảng hoặc một phạm vi.

=INDEX(array;row_num;column_num)

Trong đó:

  • array: vùng ô hoặc một hàng số mảng nào đó;
  • row_num: chọn hàng trong mảng từ đó trả về một giá trị;
  • column: chọn cột trong mảng từ đó trả về một giá trị.

Công thức hàm MATCH

Hàm MATCH trả về vị trí tương đối của một giá trị trong một phạm vi.

=MATCH(lookup_value,lookup_array,match_type)

Trong đó:

  • Lookup_value: giá trị tìm kiếm trong mảng Lookup_array.
  • Lookup_array: mảng hay phạm vị ô được tìm kiếm.
  • Match_type: kiểu tìm kiếm.

    3Ví dụ hàm INDEX kết hợp hàm MATCH


    Giả sử ta có đơn giá theo Sản phẩm và Hãng sản xuất trong Bảng 2 (B15:E18). Dựa theo bảng 2, ta cần điền đơn giá vào Bảng 1 (B3:D12).

    Điền đơn giá cho Bảng 1 dựa vào Bảng 2

    Cách ta sử dụng hàm INDEX kết hợp hàm MATCH để dò tìm giá trị cho ô D4 như sau:

    1. Sử dụng hàm MATCH để xác định vị trí hàng tương ứng của sản phẩm CDRom trong phạm vi B15:B18 của Bảng 2: 

    =MATCH(B4,$B$15:$B$18,0)

    Kết quả 4 tương ứng với hàng số 4 trong Bảng 2.

    Sử dụng hàm MATCH để xác định vị trí hàng

    2. Sử dụng hàm MATCH để xác định vị trí cột tương ứng của hãng sản xuất Samsung trong phạm vi B15:E15: 

    =MATCH(C4,$B$15:$E$15,0)

    Kết quả 2 tương ứng với cột số 2 trong Bảng 2.

    Sử dụng hàm MATCH để xác định vị trí cột

    3. Sử dụng hàm INDEX kết hợp với 2 hàm MATCH ở trên để trả về giá trị dựa theo hàng và cột trong Bảng 2: 

    =INDEX($B$15:$E$18,MATCH(B4,$B$15:$B$18,0),MATCH(C4,$B$15:$E$15,0))

    Kết quả trả về giá trị tương ứng của hàng 4 (Hàng Mouse), cột 2 (Cột Samsung) trong Bảng 2 là 5.

    Kết hợp hàm INDEX và hàm MATCH

    Sau đó, ta copy công thức cho các ô khác để hoàn thành.

    Copy công thức cho các ô khác để hoàn thành

    4Một số lưu ý khi sử dụng

    Như đã đề cập ở phần 1, vì hàm VLOOKUP, HLOOKUP có hạn chế của nó nên nếu giá trị trả về nằm ở cột bên trái hoặc cột ở trên so với giá trị dò tìm thì 2 công thức sẽ không hoạt động. Hàm INDEX kết hợp hàm MATCH sẽ linh hoạt hơn rất nhiều khi không quan tâm về vị trí các cột giá trị trả về ở đâu.

    Trong ví dụ ở dưới, ta có bảng 1 liệt kê thủ đô của các nước và cần điền dữ liệu tương ứng ở bảng 2. Trường hợp này ta không thể sử dụng hàm VLOOKUP nhưng hàm INDEX kết hợp hàm MATCH sẽ giải quyết được điều này.

    =INDEX($B$3:$C$12,MATCH(E4,$C$3:$C$12,0),1)

    Hàm INDEX kết hợp hàm MATCH thay thế hàm VLOOKUP

    5Một số lỗi thường gặp

    Trong lúc sử dụng hàm INDEX kết hợp với hàm MATCH, bạn sẽ gặp lỗi #NA và lỗi #VALUE xuất hiện. Các nguyên nhân gây ra lỗi này thường là:

    Lỗi #NA

    • Khi hàm MATCH không tìm thấy giá trị trong phạm vi dò tìm, nó trả về giá trị #N/A.
    • Khi bạn sử dụng một phạm vi trong INDEX, MATCH thay vì một giá trị, bạn cần nhấn Ctrl+Shift+Enter để chuyển về công thức mảng.
    • Khi bạn sử dụng MATCH, cần có sự nhất quán giữa giá trị trong đối số match_type và thứ tự sắp xếp các giá trị trong phạm vi dò tìm, nếu không bạn sẽ gặp giá trị #N/A.

    Lỗi #VALUE

    Nếu bạn đang sử dụng chỉ mục dưới dạng công thức mảng cùng với kết quả phù hợp để có thể dò tìm một giá trị, bạn sẽ cần chuyển công thức của bạn thành công thức mảng bằng cách nhấn Ctrl+Shift+Enter, nếu không thì bạn sẽ thấy lỗi #VALUE! xuất hiện. 

    [Tự học lập trình Java] Các biểu thức Lambda và các tham chiếu phương thức.

     

    Lập trình hướng đối tượng với Java - tinhoccoban.net

    Các biểu thức Lambda và các tham chiếu phương thức.

    Một vấn đề với các lớp vô danh là nếu thực hiện cho một lớp vô danh thì rất đơn giản, như một interface nó chỉ bao gồm một phương thức, thì cú pháp của các lớp vô danh có vẻ khó thực hiện để truyền vào chức năng các đối số cho phương thức khác, như một hành động nào nên được thực hiện khi ai đó nhấn nút. Biểu thức Lambda cho phép bạn làm điều này, để coi chức năng là đối số phương thức ,hoặc mã nguồn như dữ liệu.

    Trong phần trước, các phương thức vô danh, biểu diễn cho bạn làm thế làm để thực hiện một lớp cơ sở không có tên. Mặc dù việc này thường ngắn gọn hơn lớp được đặt tên, cho các lớp chỉ một phương thức, thậm chí các lớp vô danh có vẻ quá cồng kềnh. Biểu thức Lambda giúp thể hiện các lớp đơn phương thức một cách gọn gàng hơn.

    Trong phần này bao gồm các chủ đề sau:

    ·        Ý tưởng cho trường hợp sử dụng các biểu thức Lambda.

     Các tiếp cận 1: Tạo các phương thức để tìm các thành viên khớp với một đặc tính.

    Cách tiếp cận 2: Tạo nhiều phương thức tìm kiếm tổng quát hơn.

     Cách tiếp cận 3: Mã nguồn điều kiện tìm kiếm trong một lớp cục bộ.

     Cách tiếp cận 4: Mã nguồn điều kiện tìm kiếm trong một lớp vô danh.

    Cách tiếp cận 5: Mã nguồn điều kiện tìm kiếm bằng một biểu thức Lambda.

    Cách tiếp cận 6: Sử dụng các chức năng Interface chuẩn với các biểu thức Lambda.

    Cách tiếp cận 7: Sử dụng các biểu thức Lambda trong ứng dụng của bạn.

     Cách tiếp cận 8: Sử dụng Generics một cách rộng rãi hơn.

    Cách tiếp cận 9: Sử dụng các toán tử tổng hợp chấp nhận biểu thức Lambda như các tham số.

    ·        Các biểu thức Lambda trong ứng dụng GUI

    ·        Cú pháp của biểu thức Lambda

    ·        Truy cập các biến cục bộ trong phạm vi bao bọc nó.

    ·        Mục tiêu

    Ý tưởng trường hợp sử dụng cho các biểu thức Lambda.

    Giả sử rằng, bạn đang tạo ra một ứng dụng mạng xã hội. Bạn muốn tạo một đặc điểm đó là cho phép một quản trị viên thi hành bất kỳ một hành động nào, như gửi một tin nhắn, cho các thành viên trong ứng dụng mạng xã hội đương nhiên phải đáp ứng xác tiêu chí nhất định. Bảng 3.3 mô tả các trường hợp sử dụng chi tiết:

                                  Bảng mô tả các trường hợp sử dụng trong một mạng xã hội.


    Giả sử rằng các thành viên trong ứng dụng mạng xã hội này được đại diện bằng lớp Person:

    public class Person {
     
        public enum Sex {
            MALE, FEMALE
        }
     
        String name;
        LocalDate birthday;
        Sex gender;
        String emailAddress;
     
        public int getAge() {
            // ...
        }
     
        public void printPerson() {
            // ...
        }
    }

    Giả sử rằng các thành viên trong ứng dụng mạng xã hội này được lưu trữ trong một thể hiện danh sách List<Person>.

    Phần này bắt đầu với cách tiếp cận đơn giản cho trường hợp sử dụng này. Nó cải thiện cách tiếp cận này với lớp cục bộ và lớp vô danh, và sau đó kết thúc một cách hiệu quả và ngắn gọn và hiệu quả bằng cách sử dụng biểu thức Lambda.

    Cách tiếp cận 1: Tạo các phương thức tìm kiếm cho các thành viên phù hợp với một đặc tính.

    Một cách tiếp cận đơn giản là tạo một vài phương thức; mỗi phuowgn thức tìm các thành viên phù hợp với một đặc tính, như giới tính hoặc tuổi. Phương thức in ra các thành viên nhiều tuổi hơn một tuổi nhất định.

    public static void printPersonsOlderThan(List<Person> roster, int age) {
        for (Person p : roster) {
            if (p.getAge() >= age) {
                p.printPerson();
            }
        }
    }

    Chú ý: Một List là một Collection có thứ tự. Một collection là một đối tượng nhóm các thành phần trong một đơn vị. Collection được sử dụng để lưu trữ, lấy lại, thao tác và giao tiếp với các dữ liệu tổng hợp. Các bạn có thể tìm hiểu về Collections để hiểu rõ hơn.

    Cách tiếp cận này có thể tiềm năng làm hỏng ứng dụng của bạn, có khả năng xảy là ứng dụng không làm việc. Giả sử rằng bạn nâng cấp ứng dụng của mình và thay đổi cấu trúc của lớp Person như nội dung bao gồm các biến thành viên khác; có lẽ các bản ghi lớp và đo lường tuổi với một kiểu dữ liệu khác hoặc thuật toán khác. Bạn nên viết lại hầu hết các API để cung cấp cho sự thay đổi này. Ngoài ra , cách tiếp cận này hạn chế một cách không cần thiết; ví dụ nếu bạn muốn in các thành viên trẻ hơn một độ tuổi nhất định.

    Cách tiếp cận 2: Tạo nhiều phương thức tìm kiếm tổng quát hơn.

    Phương thức khái quát hơn printPersonsOlderThan; nó in các thành viên trong độ tuổi nhất định.

    public static void printPersonsWithinAgeRange(
        List<Person> roster, int low, int high) {
        for (Person p : roster) {
            if (low <= p.getAge() && p.getAge() < high) {
                p.printPerson();
            }
        }
    }

    Điều gì sẽ xảy ra khi bạn muốn in các thành viên có một giới tính cụ thể, hoặc một sự kết hợp của giới tính và phạm vi tuổi? Cái gì xảy ra nếu bạn quyết địnhthay đổi lớp Person và thêm các thuộc tính như mối quan hệ giữa tình trạng hoặc vị trí địa lý. Mặc dù phương thức này khái quát hơn phương thức printPersonsOlderThan, thử tạo ra các phương thức riêng biệt cho mỗi truy vấn có thể dẫn đến làm hỏng mã nguồn. Bạn có thể thay thế các mã nguồn riêng biệt bằng các điều kiện bạn muốn tìm kiếm trong lớp khác.

    Cách tiếp cận 3: Chỉ định các tiêu chí tìm kiếm trong một lớp cục bộ.

    Phương thức sau in ra các thành viên khớp với các điều kiện tìm kiếm mà bạn chỉ định.

    public static void printPersons(
        List<Person> roster, CheckPerson tester) {
        for (Person p : roster) {
            if (tester.test(p)) {
                p.printPerson();
            }
        }
    }

    Phương thức này kiểm tra mỗi cá thể của lớp Person trong một danh sách List là kiểu dữ liệu của tham số roster khi nó thỏa mã các tiêu chí tìm kiếm CheckPerson là kiểu dữ liệu của tham số tester được gọi bởi phương thức tester.test. Nếu phương thức tester.test trả về một giá trị true, thì phương thức printPersons được gọi từ cá thể Person.

    Để xác định tiêu chí tìm kiếm, bạn thực hiện interface CheckPerson:

    interface CheckPerson {
        boolean test(Person p);
    }

    Lớp sau thực hiện interface CheckPerson bằng xác định một thực hiện cho phương thức test. Phương thức này lọc các thành viên đạt chuẩn cho Selective Service trong United States: nó trả về một giá trị true nếu tham số Person là male và trong độ tuổi từ 18 tới 25.

    class CheckPersonEligibleForSelectiveService implements CheckPerson {
        public boolean test(Person p) {
            return p.gender == Person.Sex.MALE &&
                p.getAge() >= 18 &&
                p.getAge() <= 25;
        }
    }

    Để sử dụng lớp này, bạn tạo một cá thể gọi phương thức printPersons.

    printPersons(
        roster, new CheckPersonEligibleForSelectiveService());

    Mặc dù cách tiếp cận này ít làm hỏng mã nguồn hơn – bạn không được viết lại các phương thức nếu bạn thay đổi cấu trúc của lớp Person – bạn vẫn phải thêm mã nguồn: một interface mới và một lớp cục bộ cho mỗi tìm kiếm mà bạn dự định thực hiện trong ứng dụng. Bởi vì CheckPersonEligibleForSelectiveService thực hiện một interface, bạn cần sử dụng một lớp vô danh thay thế cho lớp cục bộ và bỏ qua sự cần thiết khai báo một lớp mới cho mỗi tìm kiếm.

    Cách tiếp cận 4: Code chỉ định điều kiện tìm kiếm trong một lớp vô danh

    Một trong các đối số của của lời gọi hàm printPersons là một lớp vô danh, nó lọc các thành viên hợp lệ cho Selective Service trong Hoa Kỳ: những ai trong độ tuổi từ 18 đến 25.

    printPersons(
        roster,
        new CheckPerson() {
            public boolean test(Person p) {
                return p.getGender() == Person.Sex.MALE
                    && p.getAge() >= 18
                    && p.getAge() <= 25;
            }
        }
    );

    Trong cách tiếp cận nầy giảm số lượng mã nguồn bởi vì bạn không phải tạo một lớp mới cho mỗi tìm kiếm mà bạn muốn thực hiện. Tuy nhiên, cú pháp các lớp vô danh là rất cồng kềnh vì interface CheckPerson chỉ chứa một phương thức. Trong trường hợp này, bạn cần sử dụng một biểu thức Lambda thay thế cho một lớp vô danh, được miêu tả ở phần tiếp theo.

    Cách tiếp cận 5: Tạo mã nguồn chỉ định điều kiện tìm kiếm với biểu thức Lambda.

    Interface CheckPerson là một giao diện chức năng. Một giao diện chức năng là một interface bất kỳ nó bao gồm chỉ một phương thức trừu tượng (abstract method) (sẽ học trong phần sau). (Một giao diện chức năng có thể bao từ một trở lên của phương thức mặc định hoặc phương thức tĩnh). Bởi vì một giao diện chức năng chỉ bao gồm một phương thức trừu tượng, bạn có thể bỏ sót tên của phương thức khi bạn thực hiện nó. Để làm điều này, thay thế sử dụng một biểu thức lớp vô danh, bằng sử dụng một biểu thức Lambda, nó được đánh dấu trong phương thức sau:

    printPersons(
        roster,
        (Person p) -> p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25
    );

    Nhìn cú pháp của biểu thức Lambda cho thông tin về làm thế nào để định nghĩa các biểu thức Lambda.

    Bạn có thể sử dụng một giao diện chức năng chuẩn trong chỗ đặt interface CheckPerson, nó giảm số lượng mã nguồn cần thiết.

    Cách tiếp cận 6. Sử dụng các giao diện chức năng chuẩn với biểu thức Lambda.

    Xem xét interface CheckPerson sau:

    interface CheckPerson {
        boolean test(Person p);
    }

    Đây là một interface rất đơn giản. Nó là một giao diện chức năng bởi vì nó gồm chỉ một phương thức trừu tượng. Phương thức này lấy một tham số và trả về một giá trị kiểu boolean. Phương thức khá đơn giản, nó có thể không không đáng để xác định là một phương thức trong ứng dụng của bạn. Hệ quả là JDK định nghĩa một vài giao diện chức năng chuẩn, bạn có thể tìm thấy trong gói java.util.function.

    Cho ví dụ, bạn có thể sử dụng interface Predicate<T> tại vị trí của CheckPerson. Interface này bao gồm phương thức boolean test(T t):

    interface Predicate<T> {
        boolean test(T t);
    }

    Interface Predicate<T> là một ví dụ của giao diện generic. (Tìm hiểu thêm các thông tin về generics để biết kiểu dữ liệu này). Các kiểu dữ liệu Generic (giống như các giao diện generic) chỉ định một hoặc nhiều hơn một các kiểu tham số, T. Khi bạn khai báo hoặc khởi tạo một kiểu generic với các kiểu đối số thật, bạn có một kiểu tham số hóa. Cho ví dụ, về kiểu tham số hóa Predicate<Person> như sau:

    interface Predicate<Person> {
        boolean test(Person t);
    }

    Đây là kiểu tham số hóa bao gồm một phương thức có cùng kiểu trả về và các tham số như CheckPerson.boolean, test(Person p). Hệ quả, bạn có thể sử dụng Predicate<T> trong vị trí của CheckPerson, giống như phương thức sau đây thể hiện:

    public static void printPersonsWithPredicate(
        List<Person> roster, Predicate<Person> tester) {
        for (Person p : roster) {
            if (tester.test(p)) {
                p.printPerson();
            }
        }
    }

    Kết quả là, phương thức gọi là cũng với khi bạn gọi printPersons trong cách tiếp cận thứ 3: Tạo mã nguồn chỉ định tìm kiếm trong lớp cục bộ để có thể lọc các thành viên đủ điều kiện cho Selective Service.

    printPersonsWithPredicate(
        roster,
        p -> p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25
    );

    Đây không phải là nơi duy nhất trong phương thức này có thể sử dụng biểu thức Lambda. Cách tiếp cận dưới đây, đề xuất các cách sử dụng biểu thức Lambda.

    Cách tiếp cận thứ 7: Sử dụng biểu thức Lambda trong ứng dụng của bạn.

    Xem xét lại phương thức printPersonsWithPredicate để thấy chỗ khác bạn có thể sử dụng biểu thức Lambda.

    public static void printPersonsWithPredicate(
        List<Person> roster, Predicate<Person> tester) {
        for (Person p : roster) {
            if (tester.test(p)) {
                p.printPerson();
            }
        }
    }

    Phương thức kiểm tra mỗi cá thể Person được chứa trong roster là tham số kiểu List mà nó thỏa mãn điều kiện chỉ định trong tham số tester có kiểu Predicate. Nếu một cá thể Person thỏa mãn điều kiện chỉ định bởi tester, phương thức printPerson sẽ được gọi trong cá thể Person.

    Thay thế lời gọi phương thức printPerson, bạn có thể chị định một hành động khác để thực hiện trên các cá thể Person đó là thỏa mãn điều kiện cụ thể bởi tester. Bạn có thể chị định các hành động này với một biểu thức Lambda tương tự như printPerson, một trong đó có một đối số (một đối tượng của kiểu Person) và trả về kiểu void. Nhớ rằng, để sử dụng một biểu thức Lambda, bạn cần thực hiện một giao diện chức năng. Trong trường hợp này, bạn cần một giao diện chức năng chứa một phương thức trừu tượng đó có thể lấy một đối số của kiểu Person và trả về kiểu void. Giao diện Consumer<T> chứa phương thức void accept(T t), nó có các đặc điểm đó. Phương thức sau thay thế lời gọi p.printPerson() với một cá thể của Consumer<Person> nó gọi phương thức accept.

    public static void processPersons(
        List<Person> roster,
        Predicate<Person> tester,
        Consumer<Person> block) {
            for (Person p : roster) {
                if (tester.test(p)) {
                    block.accept(p);
                }
            }
    }

    Kết quả, sau khi gọi phương thức giống với khi bạn gọi phương thức printPersons trong cách tiếp cận 3: Viết mã nguồn chỉ định tìm kiếm trong lớp cục bộ để tìm những thành viên đạt chuẩn trong Selective Service. Biểu thức Lambda sử dụng để in ra các thành viên trong phần đánh dấu:

    processPersons(
         roster,
         p -> p.getGender() == Person.Sex.MALE
             && p.getAge() >= 18
             && p.getAge() <= 25,
         p -> p.printPerson()
    );

    Điều gì sẽ xảy ra khi bạn muốn làm hơn nữa với các hồ sơ của các thành viên so với việc in chúng ra. Giả sử rằng bạn muốn xác thực các hồ sơ các thành viên hoặc lưu trữ thông tin liên hệ của họ. Trong trường hợp này, bạn cần một giao diện chức năng có chưa một phương thức trừu tượng và trả về một giá trị. Interface Function<T,R> chứa phương thứ R apply(T t). Phương thức sau truy xuất dữ liệu được chỉ định bởi trình ánh xạ tham số, sau đó thực hiện một hành động trên nó được chỉ định bởi khối tham số:

    public static void processPersonsWithFunction(
        List<Person> roster,
        Predicate<Person> tester,
        Function<Person, String> mapper,
        Consumer<String> block) {
        for (Person p : roster) {
            if (tester.test(p)) {
                String data = mapper.apply(p);
                block.accept(data);
            }
        }
    }

    Phương thức lấy địa chỉ email từ mỗi thành viên chứa trong roster những ai đạt trong Selective Service và sẽ in chúng ra:

    processPersonsWithFunction(
        roster,
        p -> p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25,
        p -> p.getEmailAddress(),
        email -> System.out.println(email)
    );

    Cách tiếp cận 8: Sử dụng Generics mở rộng.

    Xem xét phương thức processPersonsWithFunction. Phương thức sau là một phiên bản generic, nó chấp nhận như một tham số, một tập hợp chứa các phần tử của bất kỳ dữ liệu nào.

    public static <X, Y> void processElements(
        Iterable<X> source,
        Predicate<X> tester,
        Function <X, Y> mapper,
        Consumer<Y> block) {
        for (X p : source) {
            if (tester.test(p)) {
                Y data = mapper.apply(p);
                block.accept(data);
            }
        }
    }

    Để in ra địa chỉ email của các thành viên đạt chuẩn cho Selective Service, gọi phương thức processElements như sau:

    processElements(
        roster,
        p -> p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25,
        p -> p.getEmailAddress(),
        email -> System.out.println(email)
    );

    Phương thức này gọi thực thi các hành động sau:

    ·        1. Lấy một nguồn của các đối tượng từ tập hợp source. Trong trường hợp ví dụ này, nó lấy nguồn của các đối tượng Person từ tập hợp roster. Chú ý rằng tập hợp roster, nó là một tập hợp có kiểu List, cũng là một đối tượng kiểu Iterable.

    ·        2. Lọc các đối tượng phù hợp với trình kiểm tra đối tượng tester của Predicate. Trong ví dụ này, đối tượng kiểm tra Predicate là một biểu thức Lambda nó chỉ định các thành viên đạt yêu cầu cho Selective Service.

    ·        3. Ánh xạ mỗi đối tượng được lọc thành một giá trị được chỉ định bởi Function, có đối tượng là mapper. Trong ví dụ này, đối tượng Function làm một biểu thức Lambda trả về địa chỉ email của một thành viên.

    ·        4. Thực hiện một hành động trên đối tượng phù hợp được chỉ định bởi Consumer có đối tượng block. Trong trường hợp này, đối tượng Consumer là một biểu thức Lambda nó in ra một chuỗi, đó là đại chỉ email đã được trả về bởi đối tượng Function.

    Bạn có thể thay thế mỗi hành động bằng một toán tử tổng hợp.

    Cách tiếp cận 9: Sử dụng toán tử tổng hợp chấp nhận biểu thức Lambda như những tham số.

    Ví dụ sau sử dụng toán tử tổng hợp để in ra các địa chỉ email của các thành viên chứa trong tập hợp roster là những thành viên đạt tiêu chuẩn cho Selective Service.

    roster
        .stream()
        .filter(
            p -> p.getGender() == Person.Sex.MALE
                && p.getAge() >= 18
                && p.getAge() <= 25)
        .map(p -> p.getEmailAddress())
        .forEach(email -> System.out.println(email));

    Bảng sau ánh xạ mỗi toán tử ở phương thức processElements thực hiện với toán tử tổng hợp.

    Ánh xạ mỗi toán tử ở phương thức processElements thực hiện với toán tủ tổng hợp

    Ánh xạ mỗi toán tử ở phương thức processElements thực hiện với toán tủ tổng hợp - tinhoccoban.net

    Toán tử filter, mapforEach là các toán tử tổng hợp. Các toán tử tổng hợp xử lý các phần tử trong một luồng, không trực tiếp từ một tập hợp (đó là lý do tại sao lời gọi phương thức đầu tiên trong ví dụ là stream). Một stream là một tuần tự các phần tử. Không giống như tập hợp, nó không có cấu trúc dữ liệu lưu trữ các phần tử. Thay vào đó, một stream mang các giá trị từ một nguồn, giống như tập hợp, thông qua một pipeline. Một pipeline là một tuần tự của luồng các toán tử, trong ví dụ là filter-map-forEach. Ngoài ra, các toán tử tổng hợp phổ biến chấp nhận các biểu thức Lambda như các tham số, cho phép bạn tùy chỉnh cách chúng hoạt động. Các bạn cần tìm hiểu nhiều hơn về các toán tử tổng hợp này.

    Các biểu thức Lambda trong ứng dụng GUI.

    Để xử lý các sự kiện trên ứng dụng giao diện người dùng (GUI), giống như các hành động trên bàn phím, hành động trên chuột, và hành động lăn chuột, bạn thường tạo ra các trình xử lý sự kiện, chúng thường liên quan đến triển khai một giao diện cụ thể. Thông thường, trình sử lý sự kiện trên các giao diện là các giao diện chức năng; chúng có khuynh hướng chỉ có một phương thức.

    Trong ví dụ JavaFX HelloWord.Java (đã được bàn trong phần trước là các lớp vô danh), bạn có thể thay thế lớp vô danh được đánh dấu bằng một biểu thức Lambda trong câu lệnh sau:

            btn.setOnAction(new EventHandler<ActionEvent>() { 
                @Override
                public void handle(ActionEvent event) {
                    System.out.println("Hello World!");
                }
            });

    Lời gọi phương thức btn.setOnAction chỉ định cái gì xảy ra khi bạn chọn vào nút thể hiện bằng đối tượng btn. Phương thức này yêu cầu một đối tượng có kiểu EventHandler<ActionEvent>. Interface EventHandler<ActionEvent> chứa chỉ duy nhất một phương thức, void handle(T event). Interface này là giao diện chức năng, do đó bạn có thể sử dụng như sau trong phần đánh dấu dùng biểu thức Lambda thay thế.

            btn.setOnAction(
              event -> System.out.println("Hello World!")
            );

     Cú pháp của các biểu thức Lambda.

    Một biểu thức lambda bao gồm các thành phần sau:

    ·        Một danh sách các tham số hình thức được phân tách bởi dấu phẩy được đặt trong dấu ngoặc đơn. Phương thức CheckPerson.test chứa một tham số, p, nó thể hiện là một cá thể của lớp Person.

    Chú ý: Bạn có thể bỏ sót kiểu dữ liệu của các tham số trong biểu thức Lambda. Ngoài ra, bạn có thể bỏ sót dấu ngoặc đơn nếu nó chỉ có một tham số. Ví dụ sau biể thức Lamda là hợp lệ:

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25

    ·        Mã thông báo mũi tên, ->

    ·        Một thân, nó bao gồm một biểu thức đơn hoặc một khối lệnh. Trong ví dụ này sử dụng biểu thức sau:

    p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25

    Nếu bạn chỉ định một biểu thức đơn thì bộ chạy thời gian Java tính toán biểu thức và trả vê một giá trị cho nó. Ngoài ra bạn cần sử dụng một câu lệnh trả về:

    p -> {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }

    Một câu lện trả về không là một biểu thức; trong một biểu thức Lambda, bạn phải bao bọc các câu lệnh trong dấu mở đóng ngoặc nhọn ({}). Tuy nhiên, bạn không cần phải bao bọc một phương thức trả về giá trị kiểu void. Ví dụ sau đây là một biểu thức Lambda hợp lệ:

    email -> System.out.println(email)

    Chú ý rằng biểu thức Lambda nhìn tất cả giống như một khai báo phương thức; bạn có thể xem xét các biểu thức Lambda như những phương thức vô danh – các phương thức không có tên.

    Ví dụ sau, Caculator, là một ví dụ của các biểu thức Lambda có nhiều hơn một tham số hình thức.

    public class Calculator {
      
        interface IntegerMath {
            int operation(int a, int b);   
        }
      
        public int operateBinary(int a, int b, IntegerMath op) {
            return op.operation(a, b);
        }
     
        public static void main(String... args) {
        
            Calculator myApp = new Calculator();
            IntegerMath addition = (a, b) -> a + b;
            IntegerMath subtraction = (a, b) -> a - b;
            System.out.println("40 + 2 = " +
                myApp.operateBinary(40, 2, addition));
            System.out.println("20 - 10 = " +
                myApp.operateBinary(20, 10, subtraction));    
        }
    }

    Phương thức operateBinary thực hiện một thao tác phép toán trên hai toán tử số nguyên. Thao tác này chỉ định một thể hiện của IntegerMath. Ví dụ định nghĩa hai toán tử với các biểu thức Lambda, addition và subtraction. Kết quả của ví dụ như sau:

    40 + 2 = 42
    20 - 10 = 10

    Truy cập vào các biến cục bộ trong phạm vi bao bọc biểu thức Lambda.

    Giống như các lớp cục bộ và các lớp vô danh, các biểu thức Lambda có thể bắt được các biến; chúng có thể truy cập vào các biến cục bộ của khối phạm vi bao bọc nó. Tuy nhiên, không giống với các lớp vô danh, các biểu thức Lambda không làm mờ được các biến (tìm hiểu sâu hơn về làm mờ để hiểu hơn). Các biểu thức Lambda có phạm vi từ vựng. Điều này có nghĩa là chúng không kế thừa bất kỳ tên nào từ một siêu dữ liệu hoặc một giới thiệu phạm vi mới. Khai báo trong biểu thức Lambda là chỉ diễn giải như chúng trong phạm vi môi trường bao bọc nó. Ví dụ sau, LambdaScopeTest, minh họa điều này:

    import java.util.function.Consumer;
     
    public class LambdaScopeTest {
     
        public int x = 0;
     
        class FirstLevel {
     
            public int x = 1;
            
            void methodInFirstLevel(int x) {
     
                int z = 2;
                 
                Consumer<Integer> myConsumer = (y) -> 
                {
                    // The following statement causes the compiler to generate
                    // the error "Local variable z defined in an enclosing scope
                    // must be final or effectively final" 
                    //
                    // z = 99;
                    
                    System.out.println("x = " + x); 
                    System.out.println("y = " + y);
                    System.out.println("z = " + z);
                    System.out.println("this.x = " + this.x);
                    System.out.println("LambdaScopeTest.this.x = " +
                        LambdaScopeTest.this.x);
                };
     
                myConsumer.accept(x);
     
            }
        }
     
        public static void main(String... args) {
            LambdaScopeTest st = new LambdaScopeTest();
            LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
            fl.methodInFirstLevel(23);
        }
    }

    Ví dụ này có kết quả như sau:

    x = 23
    y = 23
    z = 2
    this.x = 1
    LambdaScopeTest.this.x = 0

    Nếu bạn thay thế tham số x vào thay cho y trong khai báo biểu thức Lambda myComsumer, thì trình biên dịch sẽ sinh ra lỗi:

    Consumer<Integer> myConsumer = (x) -> {
        // ...
    }

    Trình biên dịch sinh ra lỗi "Lambda expression's parameter x cannot redeclare another local variable defined in an enclosing scope" tạm dịch là “Tham sỗ của biểu thức Lambda không thể định nghĩa lại một biến khác trong phạm vi nó được bao bọc” bởi vì biểu thức Lambda không giới thiệu một cấp độ phạm vi mới. Hệ quả là bạn có thể truy cập trực tiếp vào các thuộc tính, phương thức và các biến cục bộ trong phạm vi bao bọc nó. Ví dụ, biểu thức Lambda truy cập trực tiếp tham số x của phương thức methodInFirstLevel. Để truy cập các biến trong phạm vi lớp bao bọc, sử dụng từ khóa this. Trong ví dụ này là, this.x, tham chiếu đến biến thành viên FistLevel.x.

    Tuy nhiên, giống như các lớp cục bộ và các lớp vô danh, một biểu thức Lambda chỉ có thể truy cập các biến cục bộ và các tham số trong khối bao bọc nó khi biến đó là final hoặc efectively final. Trong ví dụ này, biến z là biến effectively final; giá trị của nó không bao giờ thay đổi sau khi nó được khởi gán. Tuy nhiên, giả sử bạn thêm câu lệnh gán sau trong biểu thức Lambda myConsumer:

    Consumer<Integer> myConsumer = (y) -> {
        z = 99;
        // ...
    }

    Bởi vì câu lệnh gán này, biến z không phải là là effiectively final nữa. Kết quả, trình biên dịch Java sẽ tạo ra một lỗi tương tự như “Local variable z defined in an enclosing scope must be final or effectively final” tạm dịch là biến z được đã được định nghĩa trong khối bao bọc nó phải là final hoặc effectively final.

    Kiểu dữ liệu mục tiêu.

    Làm thế nào để bạn quyết định kiểu cho một biểu thưc Lambda? Gọi lại một biểu thức Lambda chọn các thành viên có giới tính nam và có độ tuổi từ khoảng 18 tới 25 tuổi:

    p -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25

    Trong biểu thức Lambda này đã sử dụng hai phương thức sau:

    ·        public static void printPersons(List<Person> roster, CheckPerson tester), trong cách tiếp cận 3: chỉ định điều kiện tìm kiếm trong lớp cục bộ.

    ·        public void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester), trong cách tiếp cận 6: sử dụng các giao diện chức năng chuẩn với biểu thức Lambda.

    Khi chạy chương trình Java gọi phương thức printPersons, nó chờ kiểu dữ liệu trả về là CheckPerson, do đó biểu thức Lambda là kiểu dữ liệu này. Tuy nhiên, khi chương trình Java gọi phương thức printPersonsWithPredicate nó chờ kiểu dữ liệu trả về là Predicate<Person>, do vậy biểu thức Lambda là kiểu dữ liệu này. Kiểu dữ liệu của các phương thức chờ đợi trả về gọi là kiểu dữ liệu mục tiêu. Để quyết định một kiểu cho một biểu thức Lambda, trình biên dịch Java sử dụng kiểu dữ liệu mục tiêu cho ngữ cảnh hoặc tình uống mà biểu thức Lambda được tìm thấy. Theo đó, bạn cần sử dụng chỉ một biểu thức Lambda cho tình huống mà trình biên dịch có thể quyết định kiểu dữ liệu mục tiêu:

    ·        Khai báo biến.

    ·        Câu lệnh gán

    ·        Câu lệnh trả về

    ·        Khởi gán mảng

    ·        Đối số cho phương thức hoặc hàm khởi tạo.

    ·        Thân biểu thức Lambda.

    ·        Biểu thức điểu kiện, ?:

    ·        Truyền biểu thức.

    Các kiểu dữ liệu mục tiêu và các đối số phương thức.

    Các đối số phương thức, trình biên dịch Java quyết định kiểu dữ liệu mục tiêu với hai đoặc điểm ngôn ngữ: giải quyết nạp chồng và kiểu suy luận đối số.

    Xem xét hai giao diện chức năng (java.lang.Runnablejava.util.concurrent.Callable<V>):

    public interface Runnable {
        void run();
    }
     
    public interface Callable<V> {
        V call();
    }

    Phương thức Runnable.run không trả về một giá trị, phương thức Callable<V>.call thì có.

    Hình dung rằng, bạn có nạp chồng khi gọi phương thức sau (xem lại phần định nghĩa phương thức để hiểu về phương thức nạp chồng.)

    void invoke(Runnable r) {
        r.run();
    }
     
    <T> T invoke(Callable<T> c) {
        return c.call();
    }

    Phương thức nào sẽ được gọi trong câu lệnh sau:

    String s = invoke(() -> "done");

    Phương thức invoke(Callable<T>) sẽ được gọi bởi vì nó là phương thức trả về một giá trị; phương thức invoke(Runnable) thì không. Trong trường hợp này, kiểu của biểu thức Lambda () -> "done" là Callable<T>.

    Tuần tự hóa

    Bạn có thể tuần tự hóa biểu thức Lambda nếu kiểu dữ liệu mục tiêu và các đối số bắt được có khả năng tuần tự. Tuy nhiên, như các lớp trong, việc tuần tự hóa biểu thức Lambda là không được khuyến khích.

    Bài đăng phổ biến

    Bài viết mới nhất

    Tin học cơ bản - Nền tảng của mọi kỹ năng

    Mọi thông tin trên blog đều được giữ bản quyền bởi Tin học cơ bản. Các bạn nếu muốn lấy thông tin từ blog vui lòng ghi rõ nguồn Tinhoccoban.net

    TIN HỌC CƠ BẢN