From 2dcc3aac94c72e4357526a7127f60b2b8d7e6135 Mon Sep 17 00:00:00 2001 From: ManhKM Date: Tue, 30 May 2023 14:25:16 +0700 Subject: [PATCH 1/8] Enable check file exists --- .../data/input/03/03-01/backup-data-01.txt | 0 .../data/input/03/03-01/backup-data-02.txt | 0 .../data/input/03/03-01/backup-data-03.txt | 0 .../data/input/03/03-01/backup-data.txt | 0 .../data/input/03/customer-01.txt | 0 .../data/input/03/customer-02.html | 0 .../data/input/03/customer-02.java | 0 .../data/input/03/customer-02.mp3 | 0 .../data/input/03/customer-02.mp4 | 0 .../data/input/03/customer-02.sql | 0 .../data/input/03/customer-02.txt | 0 Java-File-Manager/java-file-manager/readme.md | 25 +++++++++ .../msoft/core/crud/DirectoriesManager.java | 33 +++++++++++ .../crud/{FileInfo.java => FileManager.java} | 55 ++++++++++++++++--- 14 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-01.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-01.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-02.html create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-02.java create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-02.mp3 create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-02.mp4 create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-02.sql create mode 100644 Java-File-Manager/java-file-manager/data/input/03/customer-02.txt create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java rename Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/{FileInfo.java => FileManager.java} (63%) diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-01.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-01.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-01.txt b/Java-File-Manager/java-file-manager/data/input/03/customer-01.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-02.html b/Java-File-Manager/java-file-manager/data/input/03/customer-02.html new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-02.java b/Java-File-Manager/java-file-manager/data/input/03/customer-02.java new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-02.mp3 b/Java-File-Manager/java-file-manager/data/input/03/customer-02.mp3 new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-02.mp4 b/Java-File-Manager/java-file-manager/data/input/03/customer-02.mp4 new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-02.sql b/Java-File-Manager/java-file-manager/data/input/03/customer-02.sql new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/customer-02.txt b/Java-File-Manager/java-file-manager/data/input/03/customer-02.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/readme.md b/Java-File-Manager/java-file-manager/readme.md index 54d3abd..941da52 100644 --- a/Java-File-Manager/java-file-manager/readme.md +++ b/Java-File-Manager/java-file-manager/readme.md @@ -1,5 +1,30 @@ # Java-File-Manager +## List API sử dụng đối với File + +### Loại 1: CREATE + +Tạo file rỗng + +Tạo file với nội dung được fix trong hàm + +Tạo file với nội dung được lấy từ một Collection khác + +Tạo file với nội dung được lấy từ execute QUERY trong Database. + +Tạo file với nội dung được custom từ nội dung của file khác. + + + +### Loại 2: READ + +Đọc thông tin chi tiết, liên quan của file + +Đọc nội dung của file theo dữ liệu gốc + +Đọc nội dung của file theo chuyển đổi thành Object + + ## Reference document diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java new file mode 100644 index 0000000..ec05525 --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java @@ -0,0 +1,33 @@ +package com.msoft.core.crud; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Quản lý thông tin các thư mục + */ +public class DirectoriesManager { + + public static void main(String[] args) { + String pathDirectory = "data/input/03"; + + System.out.println(getFileOfDirectory(pathDirectory)); + } + + /** + * Lấy danh sách file số liệu theo đường dẫn thư mục được chỉ định + * @param pathDirectory + * @return + */ + private static List getFileOfDirectory(String pathDirectory) { + File file = new File(pathDirectory); + List listName = new ArrayList<>(); + String fileNames[] = file.list(); + + for (String fileName: fileNames){ + listName.add(fileName); + } + return listName; + } +} diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileInfo.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java similarity index 63% rename from Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileInfo.java rename to Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java index 0876fb6..8488f4d 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileInfo.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java @@ -5,22 +5,24 @@ import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; import java.util.Formatter; import java.util.List; import java.util.Scanner; -public class FileInfo { +public class FileManager { public static void main(String[] args) { - String pathFile = "data/input/02/info-person.txt"; + String pathFile = "data/input/03/03-01/backup-data-03.txt"; // B1: Create file and content: - int numberOfLine = 2_000; - System.out.println(createAndWriteContent2File(pathFile, numberOfLine).toString()); + // int numberOfLine = 2_000; + // System.out.println(createAndWriteContent2File(pathFile, numberOfLine).toString()); // B2: Reading conent of file: - System.out.println(readContentOfFile(pathFile)); + // System.out.println(readContentOfFile(pathFile)); + onlyCreateFileWithPathFile(pathFile); } @@ -31,7 +33,7 @@ public static void main(String[] args) { * @param pathFile * @return */ - private static FileEntity getInfoFile(String pathFile) { + private static FileEntity getInfoFileUsingPathFile(String pathFile) { File file = new File(pathFile); FileEntity fileEntity = new FileEntity(file.getName(), file.getParent(), file.getPath(), file.getAbsolutePath(), file.getAbsoluteFile().toString(), file.exists()); @@ -43,6 +45,22 @@ private static FileEntity getInfoFile(String pathFile) { } } + /** + * Khi đã chuyển đổi thông tin file từ pathFile thành Object File + * @param file - Object file sau khi đã lấy theo đường dẫn pathFile + * @return + */ + private static FileEntity getInfoFileUsingFile(File file){ + FileEntity fileEntity = new FileEntity(file.getName(), file.getParent(), file.getPath(), + file.getAbsolutePath(), file.getAbsoluteFile().toString(), file.exists()); + if (fileEntity.isExists()) { + return fileEntity; + } else { + System.out.println("File not exists...."); + return null; + } + } + /** * Tạo file và ghi nội dung vào file * @@ -57,7 +75,7 @@ private static FileEntity createAndWriteContent2File(String pathFile, int number } formatter.close(); - return getInfoFile(pathFile); + return getInfoFileUsingPathFile(pathFile); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("Can't formatter data of file..."); @@ -110,4 +128,27 @@ private static Person convertString2Object(String keyDetect, String line, int si return null; } } + + /** + * Chỉ tạo file thôi mà chưa làm gì đối với nó hết + * @param pathFile + * @return + */ + private static FileEntity onlyCreateFileWithPathFile(String pathFile){ + File file = new File(pathFile); + try { + if(file.createNewFile()){ + System.out.println("... CREATED FILE"); + return getInfoFileUsingFile(file); + } else { + System.out.println("... CAN'T CREATE FILE"); + if(file.exists()){ + System.out.println(" ... FILE EXISTS ALREADY"); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } } From 6d5463c80e3ce2f26a4524bc6ea240accaec7029 Mon Sep 17 00:00:00 2001 From: ManhKM Date: Tue, 30 May 2023 15:40:39 +0700 Subject: [PATCH 2/8] Check exit file of system --- .../msoft/core/crud/DirectoriesManager.java | 52 ++++++++++++- .../msoft/core/entity/DirectionEntity.java | 73 +++++++++++++++++++ 2 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/entity/DirectionEntity.java diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java index ec05525..8087d3f 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java @@ -1,22 +1,31 @@ package com.msoft.core.crud; +import com.msoft.core.entity.DirectionEntity; + import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; /** * Quản lý thông tin các thư mục + * ---- + * CRUD Directories: Tạo, đọc nội dung, chỉnh sửa nội dung trong thư mục, chỉnh sửa tên của thư mục, xóa tên của thư mục */ public class DirectoriesManager { public static void main(String[] args) { - String pathDirectory = "data/input/03"; + String pathDirectory = "data/input/03/03-01"; - System.out.println(getFileOfDirectory(pathDirectory)); + System.out.println(createDirectoryUsingPathDirectory(pathDirectory)); } /** * Lấy danh sách file số liệu theo đường dẫn thư mục được chỉ định + * * @param pathDirectory * @return */ @@ -25,9 +34,46 @@ private static List getFileOfDirectory(String pathDirectory) { List listName = new ArrayList<>(); String fileNames[] = file.list(); - for (String fileName: fileNames){ + for (String fileName : fileNames) { listName.add(fileName); } return listName; } + + private static DirectionEntity getInfoDirectionUsingPathDirectory(String pathDirector) { + + return null; + } + + /** + * Tạo thư mục mới sử dụng PathDirectory + * + * @param pathDirector - đường dẫn path đến thư mục cần quản lý + * @return + */ + private static DirectionEntity createDirectoryUsingPathDirectory(String pathDirector) { + Path directoryPath = Paths.get(pathDirector); + boolean isExists = Files.exists(directoryPath); + if (!isExists) { + try { + DirectionEntity directionEntity = new DirectionEntity(); + Path path = Files.createDirectories(directoryPath); + directionEntity.setName(path.getFileName().toString()); + directionEntity.setPath(path.getParent().toAbsolutePath().toString()); + directionEntity.setCountFile(Long.valueOf(path.getNameCount())); + directionEntity.setCountDirection(0L); + System.out.println("... CREATED DIRECTION "); + + return directionEntity; + } catch (IOException e) { + e.printStackTrace(); + System.out.println("... FAILED CREATE DIRECTION "); + } + } else { + System.out.println("... FILE ALREADY EXISTS"); + } + return null; + } + + } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/entity/DirectionEntity.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/entity/DirectionEntity.java new file mode 100644 index 0000000..756023f --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/entity/DirectionEntity.java @@ -0,0 +1,73 @@ +package com.msoft.core.entity; + +import java.util.List; + +public class DirectionEntity { + private String name; + private String path; + private List files; + private Long countFile; + private Long countDirection; + + public DirectionEntity() { + } + + public DirectionEntity(String name, String path, List files, Long countFile, Long countDirection) { + this.name = name; + this.path = path; + this.files = files; + this.countFile = countFile; + this.countDirection = countDirection; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public List getFiles() { + return files; + } + + public void setFiles(List files) { + this.files = files; + } + + public Long getCountFile() { + return countFile; + } + + public void setCountFile(Long countFile) { + this.countFile = countFile; + } + + public Long getCountDirection() { + return countDirection; + } + + public void setCountDirection(Long countDirection) { + this.countDirection = countDirection; + } + + @Override + public String toString() { + return "DirectionEntity{" + + "name='" + name + '\'' + + ", path='" + path + '\'' + + ", files=" + files + + ", countFile=" + countFile + + ", countDirection=" + countDirection + + '}'; + } +} From 1e7d15b32a132c3631ffc28d16f7945522551a70 Mon Sep 17 00:00:00 2001 From: ManhKM Date: Tue, 30 May 2023 15:58:01 +0700 Subject: [PATCH 3/8] Refactor service, impl in Project --- .../msoft/core/crud/DirectoriesManager.java | 60 +------ .../msoft/core/crud/DirectoriesService.java | 18 +++ .../java/com/msoft/core/crud/FileManager.java | 149 +---------------- .../com/msoft/core/crud/FilesService.java | 24 +++ .../crud/impl/DirectoriesServiceImpl.java | 74 +++++++++ .../core/crud/impl/FilesServiceImpl.java | 152 ++++++++++++++++++ 6 files changed, 275 insertions(+), 202 deletions(-) create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FilesService.java create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/FilesServiceImpl.java diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java index 8087d3f..daed83d 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java @@ -1,5 +1,6 @@ package com.msoft.core.crud; +import com.msoft.core.crud.impl.DirectoriesServiceImpl; import com.msoft.core.entity.DirectionEntity; import java.io.File; @@ -18,62 +19,9 @@ public class DirectoriesManager { public static void main(String[] args) { - String pathDirectory = "data/input/03/03-01"; + String pathDirectory = "data/input/03/03-05-manhkm"; + DirectoriesService directoriesService = new DirectoriesServiceImpl(); - System.out.println(createDirectoryUsingPathDirectory(pathDirectory)); + System.out.println(directoriesService.createDirectoryUsingPathDirectory(pathDirectory)); } - - /** - * Lấy danh sách file số liệu theo đường dẫn thư mục được chỉ định - * - * @param pathDirectory - * @return - */ - private static List getFileOfDirectory(String pathDirectory) { - File file = new File(pathDirectory); - List listName = new ArrayList<>(); - String fileNames[] = file.list(); - - for (String fileName : fileNames) { - listName.add(fileName); - } - return listName; - } - - private static DirectionEntity getInfoDirectionUsingPathDirectory(String pathDirector) { - - return null; - } - - /** - * Tạo thư mục mới sử dụng PathDirectory - * - * @param pathDirector - đường dẫn path đến thư mục cần quản lý - * @return - */ - private static DirectionEntity createDirectoryUsingPathDirectory(String pathDirector) { - Path directoryPath = Paths.get(pathDirector); - boolean isExists = Files.exists(directoryPath); - if (!isExists) { - try { - DirectionEntity directionEntity = new DirectionEntity(); - Path path = Files.createDirectories(directoryPath); - directionEntity.setName(path.getFileName().toString()); - directionEntity.setPath(path.getParent().toAbsolutePath().toString()); - directionEntity.setCountFile(Long.valueOf(path.getNameCount())); - directionEntity.setCountDirection(0L); - System.out.println("... CREATED DIRECTION "); - - return directionEntity; - } catch (IOException e) { - e.printStackTrace(); - System.out.println("... FAILED CREATE DIRECTION "); - } - } else { - System.out.println("... FILE ALREADY EXISTS"); - } - return null; - } - - } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java new file mode 100644 index 0000000..a693630 --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java @@ -0,0 +1,18 @@ +package com.msoft.core.crud; + +import com.msoft.core.entity.DirectionEntity; + +import java.util.List; + +/** + * Định nghĩa các Service cần có của một thư mục trong hệ thống + */ +public interface DirectoriesService { + List getFileOfDirectory(String pathDirectory); + + DirectionEntity getInfoDirectionUsingPathDirectory(String pathDirector); + + DirectionEntity createDirectoryUsingPathDirectory(String pathDirector); + + +} diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java index 8488f4d..4076d1d 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java @@ -1,154 +1,11 @@ package com.msoft.core.crud; -import com.msoft.core.entity.FileEntity; -import com.msoft.core.entity.Person; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Formatter; -import java.util.List; -import java.util.Scanner; +import com.msoft.core.crud.impl.FilesServiceImpl; public class FileManager { public static void main(String[] args) { - String pathFile = "data/input/03/03-01/backup-data-03.txt"; - - // B1: Create file and content: - // int numberOfLine = 2_000; - // System.out.println(createAndWriteContent2File(pathFile, numberOfLine).toString()); - - // B2: Reading conent of file: - // System.out.println(readContentOfFile(pathFile)); - onlyCreateFileWithPathFile(pathFile); - - - } - - /** - * Lấy thông tin liên quan của file - * - * @param pathFile - * @return - */ - private static FileEntity getInfoFileUsingPathFile(String pathFile) { - File file = new File(pathFile); - FileEntity fileEntity = new FileEntity(file.getName(), file.getParent(), file.getPath(), - file.getAbsolutePath(), file.getAbsoluteFile().toString(), file.exists()); - if (fileEntity.isExists()) { - return fileEntity; - } else { - System.out.println("File not exists...."); - return null; - } - } - - /** - * Khi đã chuyển đổi thông tin file từ pathFile thành Object File - * @param file - Object file sau khi đã lấy theo đường dẫn pathFile - * @return - */ - private static FileEntity getInfoFileUsingFile(File file){ - FileEntity fileEntity = new FileEntity(file.getName(), file.getParent(), file.getPath(), - file.getAbsolutePath(), file.getAbsoluteFile().toString(), file.exists()); - if (fileEntity.isExists()) { - return fileEntity; - } else { - System.out.println("File not exists...."); - return null; - } - } - - /** - * Tạo file và ghi nội dung vào file - * - * @param pathFile - * @return - */ - private static FileEntity createAndWriteContent2File(String pathFile, int numberOfLine) { - try { - Formatter formatter = new Formatter(pathFile); - for (int i = 0; i < numberOfLine; i++) { - formatter.format("%s,%s,%s", i, "KHONG MINH MANH_" + i, "NEO_" + i + "\r\n"); - } - formatter.close(); - - return getInfoFileUsingPathFile(pathFile); - } catch (FileNotFoundException e) { - e.printStackTrace(); - System.out.println("Can't formatter data of file..."); - return null; - } - } - - /** - * Đọc nội dung của File - * @param pathFile - đường dẫn path của File - * @return - */ - private static List readContentOfFile(String pathFile) { - System.out.println(" ... START READING CONTENT OF FILE"); - File file = new File(pathFile); - try { - Scanner scanner = new Scanner(file); - List list = new ArrayList<>(); - while (scanner.hasNextLine()) { - Person person = convertString2Object(",", scanner.nextLine(), 3); - list.add(person); - } - scanner.close(); - return list; - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } - } - - /** - * Chuyển đổi từ một String sang dạng Object - * @param keyDetect - keyword dùng cho việc phân tách phần tử - * @param line - đầu vào dòng dữ liệu - * @param size - kích thước số thuộc tính, phần tử trên 1 dòng - * @return - */ - private static Person convertString2Object(String keyDetect, String line, int size) { -// System.out.println(" ... CONVERT STRING TO OBJECT"); - Person person = new Person(); - if (!(line.length() == 0)) { - String[] parts = line.split(keyDetect); - if (parts.length == size) { - person.setId(Long.parseLong(parts[0])); - person.setName(parts[1]); - person.setCompany(parts[2]); - } - return person; - } else { - return null; - } - } - - /** - * Chỉ tạo file thôi mà chưa làm gì đối với nó hết - * @param pathFile - * @return - */ - private static FileEntity onlyCreateFileWithPathFile(String pathFile){ - File file = new File(pathFile); - try { - if(file.createNewFile()){ - System.out.println("... CREATED FILE"); - return getInfoFileUsingFile(file); - } else { - System.out.println("... CAN'T CREATE FILE"); - if(file.exists()){ - System.out.println(" ... FILE EXISTS ALREADY"); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - return null; + FilesService filesService = new FilesServiceImpl(); + System.out.println(filesService.getInfoFileUsingPathFile(pathFile)); } } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FilesService.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FilesService.java new file mode 100644 index 0000000..28a1c9b --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FilesService.java @@ -0,0 +1,24 @@ +package com.msoft.core.crud; + +import com.msoft.core.entity.FileEntity; +import com.msoft.core.entity.Person; + +import java.io.File; +import java.util.List; + +public interface FilesService { + + FileEntity getInfoFileUsingPathFile(String pathFile); + + FileEntity getInfoFileUsingFile(File file); + + FileEntity createAndWriteContent2File(String pathFile, int numberOfLine); + + List readContentOfFile(String pathFile); + + Person convertString2Object(String keyDetect, String line, int size); + + FileEntity onlyCreateFileWithPathFile(String pathFile); + + +} diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java new file mode 100644 index 0000000..8f3d60b --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java @@ -0,0 +1,74 @@ +package com.msoft.core.crud.impl; + +import com.msoft.core.crud.DirectoriesService; +import com.msoft.core.entity.DirectionEntity; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * Triển khai các nghiệp vụ liên quan của Directory + */ +public class DirectoriesServiceImpl implements DirectoriesService { + + public DirectoriesServiceImpl(){} + + /** + * Lấy danh sách file số liệu theo đường dẫn thư mục được chỉ định + * + * @param pathDirectory + * @return + */ + @Override + public List getFileOfDirectory(String pathDirectory) { + File file = new File(pathDirectory); + List listName = new ArrayList<>(); + String fileNames[] = file.list(); + + for (String fileName : fileNames) { + listName.add(fileName); + } + return listName; + } + + @Override + public DirectionEntity getInfoDirectionUsingPathDirectory(String pathDirector) { + return null; + } + + /** + * Tạo thư mục mới sử dụng PathDirectory + * + * @param pathDirector - đường dẫn path đến thư mục cần quản lý + * @return + */ + @Override + public DirectionEntity createDirectoryUsingPathDirectory(String pathDirector) { + Path directoryPath = Paths.get(pathDirector); + boolean isExists = Files.exists(directoryPath); + if (!isExists) { + try { + DirectionEntity directionEntity = new DirectionEntity(); + Path path = Files.createDirectories(directoryPath); + directionEntity.setName(path.getFileName().toString()); + directionEntity.setPath(path.getParent().toAbsolutePath().toString()); + directionEntity.setCountFile(Long.valueOf(path.getNameCount())); + directionEntity.setCountDirection(0L); + System.out.println("... CREATED DIRECTION "); + + return directionEntity; + } catch (IOException e) { + e.printStackTrace(); + System.out.println("... FAILED CREATE DIRECTION "); + } + } else { + System.out.println("... FILE ALREADY EXISTS"); + } + return null; + } +} diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/FilesServiceImpl.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/FilesServiceImpl.java new file mode 100644 index 0000000..e3bf088 --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/FilesServiceImpl.java @@ -0,0 +1,152 @@ +package com.msoft.core.crud.impl; + +import com.msoft.core.crud.FilesService; +import com.msoft.core.entity.FileEntity; +import com.msoft.core.entity.Person; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Formatter; +import java.util.List; +import java.util.Scanner; + +public class FilesServiceImpl implements FilesService { + + public FilesServiceImpl(){} + + /** + * Lấy thông tin liên quan của file + * + * @param pathFile + * @return + */ + @Override + public FileEntity getInfoFileUsingPathFile(String pathFile) { + File file = new File(pathFile); + FileEntity fileEntity = new FileEntity(file.getName(), file.getParent(), file.getPath(), + file.getAbsolutePath(), file.getAbsoluteFile().toString(), file.exists()); + if (fileEntity.isExists()) { + return fileEntity; + } else { + System.out.println("File not exists...."); + return null; + } + } + + /** + * Khi đã chuyển đổi thông tin file từ pathFile thành Object File + * + * @param file - Object file sau khi đã lấy theo đường dẫn pathFile + * @return + */ + @Override + public FileEntity getInfoFileUsingFile(File file) { + FileEntity fileEntity = new FileEntity(file.getName(), file.getParent(), file.getPath(), + file.getAbsolutePath(), file.getAbsoluteFile().toString(), file.exists()); + if (fileEntity.isExists()) { + return fileEntity; + } else { + System.out.println("File not exists...."); + return null; + } + } + + /** + * Tạo file và ghi nội dung vào file + * + * @param pathFile + * @return + */ + @Override + public FileEntity createAndWriteContent2File(String pathFile, int numberOfLine) { + try { + Formatter formatter = new Formatter(pathFile); + for (int i = 0; i < numberOfLine; i++) { + formatter.format("%s,%s,%s", i, "KHONG MINH MANH_" + i, "NEO_" + i + "\r\n"); + } + formatter.close(); + + return getInfoFileUsingPathFile(pathFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + System.out.println("Can't formatter data of file..."); + return null; + } + } + + /** + * Đọc nội dung của File + * + * @param pathFile - đường dẫn path của File + * @return + */ + @Override + public List readContentOfFile(String pathFile) { + System.out.println(" ... START READING CONTENT OF FILE"); + File file = new File(pathFile); + try { + Scanner scanner = new Scanner(file); + List list = new ArrayList<>(); + while (scanner.hasNextLine()) { + Person person = convertString2Object(",", scanner.nextLine(), 3); + list.add(person); + } + scanner.close(); + return list; + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Chuyển đổi từ một String sang dạng Object + * + * @param keyDetect - keyword dùng cho việc phân tách phần tử + * @param line - đầu vào dòng dữ liệu + * @param size - kích thước số thuộc tính, phần tử trên 1 dòng + * @return + */ + @Override + public Person convertString2Object(String keyDetect, String line, int size) { + Person person = new Person(); + if (!(line.length() == 0)) { + String[] parts = line.split(keyDetect); + if (parts.length == size) { + person.setId(Long.parseLong(parts[0])); + person.setName(parts[1]); + person.setCompany(parts[2]); + } + return person; + } else { + return null; + } + } + + /** + * Chỉ tạo file thôi mà chưa làm gì đối với nó hết + * + * @param pathFile + * @return + */ + @Override + public FileEntity onlyCreateFileWithPathFile(String pathFile) { + File file = new File(pathFile); + try { + if (file.createNewFile()) { + System.out.println("... CREATED FILE"); + return getInfoFileUsingFile(file); + } else { + System.out.println("... CAN'T CREATE FILE"); + if (file.exists()) { + System.out.println(" ... FILE EXISTS ALREADY"); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} From e32e1e87894a678b0fabc5c8b37c9a42739b89b4 Mon Sep 17 00:00:00 2001 From: Khong Minh Manh Date: Wed, 7 Jun 2023 09:41:00 +0700 Subject: [PATCH 4/8] Add content compare ConcurrentHashMap vs HashMap... --- Java-Collection/concurrent-hashmap/readme.md | 34 ++++++++++++++++++- .../ConcurrentHashMapVsSynchronizedMap.java | 2 +- .../core/{crud => }/DirectoriesManager.java | 0 .../msoft/core/{crud => }/FileManager.java | 0 4 files changed, 34 insertions(+), 2 deletions(-) rename Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/{crud => }/DirectoriesManager.java (100%) rename Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/{crud => }/FileManager.java (100%) diff --git a/Java-Collection/concurrent-hashmap/readme.md b/Java-Collection/concurrent-hashmap/readme.md index b63a04c..d0037a7 100644 --- a/Java-Collection/concurrent-hashmap/readme.md +++ b/Java-Collection/concurrent-hashmap/readme.md @@ -1,13 +1,45 @@ ## ConcurrentHashMap -1. Khi nào thì lên sử dụng ConcurrentHashMap +### 1. Khi nào thì lên sử dụng ConcurrentHashMap +|STT|Vấn đề| +|---|---| +|1|Bạn nên sử dụng ConcurrentHashMap khi bạn cần tính đồng bộ trong dự án của bạn| +|2|Thread safe mà không cần đồng bộ hóa toàn bộ map.| +|3|Đọc có thể xảy ra rất nhanh trong khi ghi được thực hiện với một khóa.| +|4|Không có khóa ở cấp độ object.| +|5|ConcurrentHashMap không ném ra một ConcurrentModificationException nếu một luồng cố gắng sửa đổi nó trong khi một luồng khác đang lặp qua nó.| +|6|ConcurrentHashMap sử dụng vô số khóa.| + + +### 2. Vấn đề về SynchronizedHashMap + +|STT|Vấn đề| +|---|---| +|1|Đồng bộ hóa ở mức độ Object.| +|2|Mọi hoạt động đọc / ghi cần phải có khóa.| +|3|Khóa toàn bộ thực thể collection là vấn đề đau đầu về hiệu suất.| +|4|Về cơ bản, điều này cho phép chỉ một luồng truy cập toàn bộ map và chặn tất cả các luồng khác.| +|5|Nó có thể gây ra việc tranh chấp tài nguyên.| +|6|SynchronizedHashMap trả về Iterator, nó có thể thất bại trong việc sửa đổi đồng thời.| ## Bài toán +Yêu cầu bài toán + +|STT|Yêu cầu| +|---|---| +|1|Tạo class ConcurrentHashMapVsSynchronizedHashMap.java| +|2|Tạo object HashTable, SynchronizedMap và ConcurrentHashMap| +|3|Thêm mới và truy xuất 1 triệu entries với Map| +|4|Đo lường thời gian bắt đầu và kết thúc => milliseconds| +|5|Sử dụng ExecutorService để chạy 10 luồng(threads) song song| + +Qua ví dụ Testing hiệu năng có thể thấy ConcurrentHashMap là có hiệu suất tốt nhất, thời gian sử lý nhất, hoàn thiện các yêu cầu. + ## Reference document: diff --git a/Java-Collection/concurrent-hashmap/src/com/core/ConcurrentHashMapVsSynchronizedMap.java b/Java-Collection/concurrent-hashmap/src/com/core/ConcurrentHashMapVsSynchronizedMap.java index 6ce283b..94d2311 100644 --- a/Java-Collection/concurrent-hashmap/src/com/core/ConcurrentHashMapVsSynchronizedMap.java +++ b/Java-Collection/concurrent-hashmap/src/com/core/ConcurrentHashMapVsSynchronizedMap.java @@ -20,7 +20,7 @@ */ public class ConcurrentHashMapVsSynchronizedMap { public final static int THREAD_POOL_SIZE = 10; - public final static int DATA_SIZE = 1000000; + public final static int DATA_SIZE = 1_000_000; public static Map hashTable = null; public static Map synchronizedMap = null; diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/DirectoriesManager.java similarity index 100% rename from Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesManager.java rename to Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/DirectoriesManager.java diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/FileManager.java similarity index 100% rename from Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/FileManager.java rename to Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/FileManager.java From d7d4e305ad2b25d06ff97c9170fcf9f519f2f7ea Mon Sep 17 00:00:00 2001 From: ManhKM Date: Mon, 10 Jul 2023 21:41:34 +0700 Subject: [PATCH 5/8] Add and Refactor project --- Java-Collection/java-deque/pom.xml | 16 + .../src/main/java/com/core/QueueExample.java | 36 + Java-DateTime/pom.xml | 16 + .../src/main/java/com/core/DateDemo.java | 14 + .../src/main/java/com/core/JobTimeDemo.java | 32 + .../src/main/java/com/core/TimeUnitDemo.java | 23 + .../input/03/03-01-temp/backup-data-01.txt | 0 .../input/03/03-01-temp/backup-data-02.txt | 0 .../input/03/03-01-temp/backup-data-03.txt | 0 .../data/input/03/03-01-temp/backup-data.txt | 0 .../data/input/03/03-01/backup-data-02.txt | 1 + .../data/input/03/03-01/backup-data-03.txt | 1 + .../data/input/03/03-01/manhkm01.txt | 1 + .../data/input/03/03-01/manhkm02.txt | 3 + .../src/main/java/com/msoft/core/App.java | 2 +- .../com/msoft/core/DirectoriesManager.java | 23 +- .../main/java/com/msoft/core/FileManager.java | 3 +- .../main/java/com/msoft/core/MonitorFile.java | 13 + .../msoft/core/crud/DirectoriesService.java | 4 + .../crud/impl/DirectoriesServiceImpl.java | 71 +- .../com/msoft/core/monitor/FileWatcher.java | 8 + .../core/monitor/impl/FileWatcherImpl.java | 80 +++ Java-Lambda/.gitignore | 33 + Java-Lambda/gpcoder.com.md | 674 ++++++++++++++++++ Java-Lambda/readme.md | 7 + .../src/core/gpcoder/SortJava8Example.java | 20 + .../core/gpcoder/SortJava8LambdaExample.java | 29 +- 27 files changed, 1093 insertions(+), 17 deletions(-) create mode 100644 Java-Collection/java-deque/pom.xml create mode 100644 Java-Collection/java-deque/src/main/java/com/core/QueueExample.java create mode 100644 Java-DateTime/pom.xml create mode 100644 Java-DateTime/src/main/java/com/core/DateDemo.java create mode 100644 Java-DateTime/src/main/java/com/core/JobTimeDemo.java create mode 100644 Java-DateTime/src/main/java/com/core/TimeUnitDemo.java create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-01.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-02.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-03.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm01.txt create mode 100644 Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm02.txt create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/MonitorFile.java create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/FileWatcher.java create mode 100644 Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/impl/FileWatcherImpl.java create mode 100644 Java-Lambda/.gitignore diff --git a/Java-Collection/java-deque/pom.xml b/Java-Collection/java-deque/pom.xml new file mode 100644 index 0000000..4200a0d --- /dev/null +++ b/Java-Collection/java-deque/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + com.core + java-deque + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/Java-Collection/java-deque/src/main/java/com/core/QueueExample.java b/Java-Collection/java-deque/src/main/java/com/core/QueueExample.java new file mode 100644 index 0000000..aa07eb8 --- /dev/null +++ b/Java-Collection/java-deque/src/main/java/com/core/QueueExample.java @@ -0,0 +1,36 @@ +package com.core; + +import java.util.ArrayDeque; + +/** + * Lưu ý rằng: ArrayQueue không phải là một thread-safe. + * Nếu sử dụng trong môi trường đa luồng, hãy đảm bảo rằng đã đồng bộ hóa truy cập đến nó. + */ +public class QueueExample { + public static void main(String[] args) { + ArrayDeque queue = new ArrayDeque<>(); + + // Thêm phần từ vào hàng đợi: + queue.addLast("First"); + queue.addLast(1); + queue.addLast(2); + queue.addLast(3); + queue.addLast(3.14); + queue.addLast("The End"); + + // Lấy và in ra phần từ đầu hàng đợi: + System.out.println("First element: " + queue.getFirst()); + + // Xóa phần từ đầu hàng đợi: + System.out.println("Delete success first element: " + queue.removeFirst()); + + // IN ra số lượng phần tử trong hàng đợi: + System.out.println("Size of queue: " + queue.size()); + + // In ra số lượng các phần từ còn lại: + System.out.println("List data of queue: "); + for (Object element : queue){ + System.out.print(element + ", "); + } + } +} diff --git a/Java-DateTime/pom.xml b/Java-DateTime/pom.xml new file mode 100644 index 0000000..c0d4e51 --- /dev/null +++ b/Java-DateTime/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + com.core + Java-DateTime + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/Java-DateTime/src/main/java/com/core/DateDemo.java b/Java-DateTime/src/main/java/com/core/DateDemo.java new file mode 100644 index 0000000..4295698 --- /dev/null +++ b/Java-DateTime/src/main/java/com/core/DateDemo.java @@ -0,0 +1,14 @@ +package com.core; + +import java.util.Date; + +public class DateDemo { + public static void main(String[] args) { + Date date1 = new Date(); + + long millis = System.currentTimeMillis(); + Date date2 = new Date(millis); + + + } +} diff --git a/Java-DateTime/src/main/java/com/core/JobTimeDemo.java b/Java-DateTime/src/main/java/com/core/JobTimeDemo.java new file mode 100644 index 0000000..005de20 --- /dev/null +++ b/Java-DateTime/src/main/java/com/core/JobTimeDemo.java @@ -0,0 +1,32 @@ +package com.core; + +public class JobTimeDemo { + + private static int sum() { + int sum = 0; + for (int i = 0; i <= 10_000; i++) { + sum += i; + System.out.print(" >>> execute sum[" + i + "]"); + } + return sum; + } + + private static void doJob(int count) { + for (int i = 0; i < count; i++) { + System.out.println(">>> execute doJob[" + i + "]"); + sum(); + } + } + + public static void main(String[] args) { + long millis1 = System.currentTimeMillis(); + doJob(100_000_000); + + long millis2 = System.currentTimeMillis(); + + long distance = millis2 - millis1; + + System.out.println("Distance time in milli second: " + distance); + } + +} diff --git a/Java-DateTime/src/main/java/com/core/TimeUnitDemo.java b/Java-DateTime/src/main/java/com/core/TimeUnitDemo.java new file mode 100644 index 0000000..5f344c5 --- /dev/null +++ b/Java-DateTime/src/main/java/com/core/TimeUnitDemo.java @@ -0,0 +1,23 @@ +package com.core; + +import java.util.concurrent.TimeUnit; + +public class TimeUnitDemo { + public static void main(String[] args) { + int minute = 5; + int millisecond = minute * 60 * 1_000; + + // Sử dụng TimeUnit; + long millisecond2 = TimeUnit.MINUTES.toMillis(minute); + + System.out.println("Case 1: " + millisecond); + System.out.println("Case 2: " + millisecond2); + + // Chuyển đổi nano giây: + long nanos = TimeUnit.MINUTES.toNanos(minute); + System.out.println("Nanos: " + nanos); + + long hours = TimeUnit.MINUTES.toHours(minute); + System.out.println("Hours: " + hours); + } +} diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-01.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-01.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-02.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-02.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-03.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data-03.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01-temp/backup-data.txt new file mode 100644 index 0000000..e69de29 diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt index e69de29..66692ac 100644 --- a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt +++ b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-02.txt @@ -0,0 +1 @@ +NEO Company \ No newline at end of file diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt index e69de29..e5c4645 100644 --- a/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt +++ b/Java-File-Manager/java-file-manager/data/input/03/03-01/backup-data-03.txt @@ -0,0 +1 @@ +Thái Bình \ No newline at end of file diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm01.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm01.txt new file mode 100644 index 0000000..930d85f --- /dev/null +++ b/Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm01.txt @@ -0,0 +1 @@ +manhkm \ No newline at end of file diff --git a/Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm02.txt b/Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm02.txt new file mode 100644 index 0000000..b681456 --- /dev/null +++ b/Java-File-Manager/java-file-manager/data/input/03/03-01/manhkm02.txt @@ -0,0 +1,3 @@ +Khong Minh Manh +NEO +Thái Bình \ No newline at end of file diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/App.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/App.java index 608b04e..42bf65b 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/App.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/App.java @@ -10,7 +10,7 @@ public class App { public static void main(String[] args) { FileUtil fileUtil = new FileUtil(); - String path = "work/wait/register"; + String path = "data/input/03"; fileUtil.discovery(path, false); } } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/DirectoriesManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/DirectoriesManager.java index daed83d..9aedb6c 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/DirectoriesManager.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/DirectoriesManager.java @@ -1,27 +1,24 @@ -package com.msoft.core.crud; +package com.msoft.core; +import com.msoft.core.crud.DirectoriesService; import com.msoft.core.crud.impl.DirectoriesServiceImpl; -import com.msoft.core.entity.DirectionEntity; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; /** * Quản lý thông tin các thư mục * ---- - * CRUD Directories: Tạo, đọc nội dung, chỉnh sửa nội dung trong thư mục, chỉnh sửa tên của thư mục, xóa tên của thư mục + * CRUD Directories: Tạo, đọc nội dung, + * chỉnh sửa nội dung trong thư mục, + * chỉnh sửa tên của thư mục, + * xóa tên của thư mục */ public class DirectoriesManager { public static void main(String[] args) { - String pathDirectory = "data/input/03/03-05-manhkm"; + String pathDirectory = "data/input/03/03-06"; DirectoriesService directoriesService = new DirectoriesServiceImpl(); - System.out.println(directoriesService.createDirectoryUsingPathDirectory(pathDirectory)); + String sourceDirectory = "data/input/03/03-01-temp"; + String targetDirectory = "data/input/03/03-08898"; + System.out.println(directoriesService.copyDirectory(sourceDirectory, targetDirectory)); } } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/FileManager.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/FileManager.java index 4076d1d..a7c17a4 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/FileManager.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/FileManager.java @@ -1,5 +1,6 @@ -package com.msoft.core.crud; +package com.msoft.core; +import com.msoft.core.crud.FilesService; import com.msoft.core.crud.impl.FilesServiceImpl; public class FileManager { diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/MonitorFile.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/MonitorFile.java new file mode 100644 index 0000000..98e71a7 --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/MonitorFile.java @@ -0,0 +1,13 @@ +package com.msoft.core; + +import com.msoft.core.monitor.FileWatcher; +import com.msoft.core.monitor.impl.FileWatcherImpl; + +public class MonitorFile { + public static void main(String[] args) { + System.out.println("----- MONITOR FILE -----"); + FileWatcher fileWatcher = new FileWatcherImpl(); + + fileWatcher.run(); + } +} diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java index a693630..e710797 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/DirectoriesService.java @@ -14,5 +14,9 @@ public interface DirectoriesService { DirectionEntity createDirectoryUsingPathDirectory(String pathDirector); + Boolean renameDirectory(String currentPathDirectory, String newPathDirectory); + Boolean deleteDirectory(String pathDirector); + + Boolean copyDirectory(String sourceDirectory, String targetDirectory); } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java index 8f3d60b..abcc592 100644 --- a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/crud/impl/DirectoriesServiceImpl.java @@ -16,7 +16,8 @@ */ public class DirectoriesServiceImpl implements DirectoriesService { - public DirectoriesServiceImpl(){} + public DirectoriesServiceImpl() { + } /** * Lấy danh sách file số liệu theo đường dẫn thư mục được chỉ định @@ -71,4 +72,72 @@ public DirectionEntity createDirectoryUsingPathDirectory(String pathDirector) { } return null; } + + /** + * Hàm sửa tên của thư mục + * + * @param currentPathDirectory + * @param newPathDirectory + * @return + */ + @Override + public Boolean renameDirectory(String currentPathDirectory, String newPathDirectory) { + Path currentPath = Paths.get(currentPathDirectory); + Path newPath = Paths.get(newPathDirectory); + + try { + Files.move(currentPath, newPath); + System.out.println("RENAME SUCCESS..."); + return true; + } catch (IOException e) { + e.printStackTrace(); + System.out.println("CANNOT RENAME FILE..."); + return false; + } + } + + @Override + public Boolean deleteDirectory(String pathDirector) { + Path path = Paths.get(pathDirector); + + try { + if (!Files.isDirectory(path)) { + System.out.println("NOT A DIRECTORY"); + return false; + } + if (Files.list(path).findFirst().isPresent()) { + System.out.println("DIRECTORY CONTAINS FILES"); + return false; + } + Files.delete(path); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public Boolean copyDirectory(String sourceDirectory, String targetDirectory) { + Path sourcePath = Paths.get(sourceDirectory); + Path targetPath = Paths.get(targetDirectory); + + try { + if (!Files.exists(targetPath)) { + Files.createDirectories(targetPath); + } + Files.walk(sourcePath).forEach(source -> { + Path target = targetPath.resolve(sourcePath.relativize(source)); + try { + Files.copy(source, target); + } catch (IOException e) { + e.printStackTrace(); + } + }); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } } diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/FileWatcher.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/FileWatcher.java new file mode 100644 index 0000000..227efc9 --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/FileWatcher.java @@ -0,0 +1,8 @@ +package com.msoft.core.monitor; + +import java.util.Map; + +public interface FileWatcher extends Runnable{ + + Map getFileMonitor(String pathDirectory); +} diff --git a/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/impl/FileWatcherImpl.java b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/impl/FileWatcherImpl.java new file mode 100644 index 0000000..fded5a9 --- /dev/null +++ b/Java-File-Manager/java-file-manager/src/main/java/com/msoft/core/monitor/impl/FileWatcherImpl.java @@ -0,0 +1,80 @@ +package com.msoft.core.monitor.impl; + +import com.msoft.core.monitor.FileWatcher; + +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class FileWatcherImpl implements FileWatcher { + /** + * Xử lý các vấn đề monitor file + * Đường dẫn tuyệt đối của file + Thời gian sửa đổi lần cuối + * + * @param pathDirectory + * @return + */ + @Override + public Map getFileMonitor(String pathDirectory) { + + // Lưu thông tin của file trong thư mục cần monitor + Map mapFile = new HashMap<>(); + + try { + // Tạo một WatchService: + WatchService watchService = FileSystems.getDefault().newWatchService(); + + // Đường dẫn đến thư mục muốn theo dõi: + Path directory = Paths.get(pathDirectory); + + // Đăng ký thư mục với WatchService để bắt sự kiện: + directory.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); + + // Vòng lặp để bắt sự kiện: + while (true) { + WatchKey key = null; + try { + key = watchService.take(); + } catch (InterruptedException e) { + return Collections.emptyMap(); + } + + // Xử lý các sự kiện trong WatchKey: + for (WatchEvent event : key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + + // Kiểm tra loại sự kiện là chỉnh sửa file + if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { + // Lấy tên file đã được thay đổi + WatchEvent pathEvent = (WatchEvent) event; + Path path = pathEvent.context(); + File file = path.toFile(); + System.out.println("File: " + file.getAbsolutePath() + ", đã được chỉnh sửa: " + file.lastModified()); + mapFile.put(file.getAbsolutePath(), file.lastModified()); + } + } + + // Reset WatchKey để tiếp tục theo dõi sự kiện + boolean valid = key.reset(); + + // Nếu WatchKey không còn hợp lệ (ví dụ: thư mục bị xóa), thoát khỏi vòng lặp + if (!valid) { + break; + } + } + } catch (IOException e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + return mapFile; + } + + @Override + public void run() { + System.out.println(" execute method run/FileWatcherImpl"); + this.getFileMonitor("data/input/03/03-01"); + } +} diff --git a/Java-Lambda/.gitignore b/Java-Lambda/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/Java-Lambda/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/Java-Lambda/gpcoder.com.md b/Java-Lambda/gpcoder.com.md index e69de29..aa22127 100644 --- a/Java-Lambda/gpcoder.com.md +++ b/Java-Lambda/gpcoder.com.md @@ -0,0 +1,674 @@ +## Biểu thức Lambda trong Java 8 – Lambda Expressions + +Đăng vào 07/05/2018 . Được đăng bởi GP Coder . 28192 Lượt xem . Toàn màn hình + +Lambda Expressions (Biểu thức Lambda) là một trong những tính năng mới được giới thiệu trong Java 8. + +Trước khi Java 8, mọi thứ chủ yếu là hướng đối tượng. Ngoại trừ các kiểu dữ liệu nguyên thủy (primitive type), mọi thứ trong java tồn tại dưới dạng đối tượng. Tất cả các lời gọi đến các method/ function sẽ được thực hiện bằng cách sử dụng các class hoặc object. Các method/ function không tồn tại độc lập. + +Với Java 8, lập trình chức năng (functional programming) đã được giới thiệu. Vì vậy, chúng ta có thể dễ dàng sử dụng các chức năng ẩn danh (anonymous functions). Nó tạo điều kiện cho các lập trình viên lập trình Functional và phát triển ứng dụng đơn giản hơn rất nhiều so với những phiên bản trước đó. Nó cung cấp một cách rõ ràng và ngắn ngọn để đại diện cho một Functional Interface sử dụng một biểu thức lamda. + +### 1. Lambda expression là gì ? +Lambda Expression (biểu thức Lambda) có thể được định nghĩa là một hàm ẩn danh, cho phép người dùng chuyển các phương thức làm đối số. Điều này giúp loại bỏ rất nhiều mã soạn sẵn. + +Lambda Expression là một hàm không có tên và không thuộc bất kỳ lớp nào, không có phạm vi truy cập (private, public hoặc protected), không khai báo kiểu trả về. + +#### 1.1. Tại sao sử dụng biểu thức Lambda? +Cung cấp bản implement cho Functional interface. + +Viết ít code hơn. + +Hiệu quả hơn nhờ hỗ trợ thực hiện tuần tự (sequential) và song song (parallel) thông qua Stream API. + +#### 1.2. Cú pháp của biểu thức Lambda + +``` java +(argument-list) -> {body} +``` + +Biểu thức Lambda trong java gồm có 3 thành phần sau: + +Argument-list: có thể không có, có một hoặc nhiều tham số + +Arrow-token: được sử dụng để liên kết arguments-list và body của biểu thức. + +Body: chứa các biểu thức và câu lệnh cho biểu thức lambda. + +Chúng ta có thể viết lambda expression bằng nhiều cách tùy thuộc vào việc sử dụng nó trong một số trường hợp như sau: + ++ Tùy chọn khai báo kiểu dữ liệu: Bạn không cần phải khai báo kiểu dữ liệu cho các parameter truyền vào. Trình biên dịch sẽ tự suy luận ra kiểu dữ liệu từ giá trị của các parameter. + ++ Tùy chọn sử dụng dấu ngoặc (): Trong trường hợp bạn chỉ truyền vào một parameter duy nhất thì chúng ta có thể bỏ qua cặp dấu ngoặc (). Nếu như có nhiều parameter thì phải sử dụng dấu ngoặc. + ++ Tùy chọn sử dụng dấu ngoặc {}: Trong trường hợp phần body code của chúng ta chỉ thực hiện 1 statement duy nhất thì chúng ta cũng có thể loại bỏ luôn cặp dấu ngoặc {}. + ++ Tùy chọn sử dụng lệnh return: Trong biểu thức Lambda, nếu chỉ có một câu lệnh, bạn có thể sử dụng hoặc không sử dụng từ khoá return. Bạn phải sử dụng từ khóa return khi biểu thức lambda chứa nhiều câu lệnh. + +```java +// No argument and one-statement method body + +() -> expression + +// One argument and one-statement method body + +(parameters) -> expression + +// Arguments separated by commas and block body + +(arg1, arg2, ...) -> { +body-block +} + +// With arguments and block body, return value + +(arg1, arg2, ...) -> { +body-block; +return return-value; +} +``` + +#### 1.3. So sánh Lambda expression vs method + +Một phương thức (method/ function) trong Java gồm các phần chính sau: + +Name: tên phương thức. + +Parameter list: danh sách các tham số. + +Body: biểu thức, câu lệnh xử lý. + +return type: kiểu dữ liệu trả về. + +Một biểu thức Lambda (Lambda expression) trong Java gồm các phần chính sau: + +No name: không có tên phương thức, nó là một phương thức ẩn danh (anonymous method). +Parameter list: danh sách các tham số. +Body: biểu thức, câu lệnh xử lý. +No return type: không có kiểu trả về tường minh, trình biên dịch Java 8 có thể tự suy luận ra kiểu dữ liệu trả về dựa vào code thực thi. +Sử dụng biểu thức Lambda +Để sử dụng biểu thức lambda, chúng ta cần tạo Functional interface của riêng mình hoặc sử dụng Functional interface do Java cung cấp. Một interface chỉ có 1 phương thức trừu tượng duy nhất được gọi là Functional interface. Ví dụ: Runnable, callable, Comparator, … + +#### 1.4. Sử dụng Functional interface: + +Trước Java 8: chúng ta tạo anonymous inner classes. +Từ Java 8: sử dụng biểu thức lambda thay vì các anonymous inner classes. +Ví dụ sử dụng biểu thức Lambda +Ví dụ cách sắp xếp một tập hợp có sẵn trước phiên bản Java 8 + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +package com.gpcoder.Lambda; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class SortBefore8Example { + + public static void main(String[] args) { + + List languages = Arrays.asList("Java", "C#", "C++", "PHP", "Javascript"); + + Collections.sort(languages, new Comparator() { + + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + + }); + + for (String language : languages) { + System.out.println(language); + } + } +} +Sử dụng Lambda của Java 8 ta có thể viết lại như sau: + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +package com.gpcoder.Lambda; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SortJava8Example { + + public static void main(String[] args) { + + List languages = Arrays.asList("Java", "C#", "C++", "PHP", "Javascript"); + + Collections.sort(languages, (String o1, String o2) -> { + return o1.compareTo(o2); + }); + + for (String language : languages) { + System.out.println(language); + } + } +} +Như bạn thấy sử dụng biểu thức Lambda code của chúng ta ngắn gọn hơn rất nhiều. Chúng ta không cần viết tên interface, tên phương thức. + +Trong một khối lệnh nếu chỉ có một lệnh duy nhất, ta có thể bỏ đi { }, khi đó đoạn code trên bạn có thể viết như sau: + +1 +Collections.sort(languages, (String o1, String o2) -> o1.compareTo(o2) ); +Trình biên dịch (Compiler) của Java có thể biết được kiểu phần tử trong tập hợp cần sắp xếp là kiểu gì, trong ví dụ này là kiểu String, và vì vậy bộ so sánh ( Comparator) chắc chắn là so sánh các kiểu dữ liệu String. Đoạn code trên có thể viết ngắn gọn hơn như sau: + +1 +Collections.sort(languages, (o1, o2) -> o1.compareTo(o2)); +Các ví dụ khác với biểu thức Lambda +Một biểu thức lambda có thể có không, một hoặc nhiều tham số. Số lượng tham số của biểu thức Lambda phụ thuộc vào số lượng tham số của phương thức trừu tượng của Functional Interface. + +Hãy xem các ví dụ sau: + +Ví dụ biểu thức Lambda không có tham số +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +package com.gpcoder.Lambda; + +@FunctionalInterface +interface Sayable1 { +public String say(); +} + +public class LambdaExpression_1 { +public static void main(String[] args) { +Sayable1 s = () -> { +return "I have nothing to say."; +}; +System.out.println(s.say()); +} +} +Ví dụ biểu thức Lambda có một tham số duy nhất +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +package com.gpcoder.Lambda; + +@FunctionalInterface +interface Sayable2 { +public String say(String name); +} + +public class LambdaExpression2 { +public static void main(String[] args) { + + // Lambda expression with single parameter. + Sayable2 s1 = (name) -> { + return "Hello, " + name; + }; + System.out.println(s1.say("GP Coder")); + + // Shorter + Sayable2 s2 = name -> { + return "Hello, " + name; + }; + System.out.println(s2.say("GP Coder")); + + // Shortest + Sayable2 s3 = name -> "Hello, " + name; + System.out.println(s3.say("GP Coder")); + } +} +Ví dụ biểu thức Lambda có nhiều tham số, sử dụng hoặc không sử dụng từ khóa return +Trong biểu thức Lambda, nếu chỉ có một câu lệnh, bạn có thể sử dụng hoặc không sử dụng từ khoá return. Bạn phải sử dụng từ khóa return khi biểu thức lambda chứa nhiều câu lệnh. + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +package com.gpcoder.Lambda; + +@FunctionalInterface +interface Addable { +int add(int a, int b); +} + +public class LambdaExpression3 { + + public static void main(String[] args) { + + // Multiple parameters with data type in lambda expression + Addable ad1 = (int a, int b) -> (a + b); + System.out.println(ad1.add(10, 20)); + + // Multiple parameters in lambda expression + Addable ad2 = (a, b) -> (a + b); + System.out.println(ad2.add(10, 20)); + + // Lambda expression without return keyword. + Addable ad3 = (a, b) -> (a + b); + System.out.println(ad3.add(10, 20)); + + // Lambda expression with return keyword. + Addable ad4 = (a, b) -> { + return (a + b); + }; + System.out.println(ad4.add(10, 20)); + + // Lambda expression without return keyword. + Addable ad5 = (a, b) -> (a + b); + System.out.println(ad5.add(10, 20)); + + // Lambda expression with multi-statement + Addable ad6 = (a, b) -> { + int sum = (a + b); + return sum; + }; + System.out.println(ad6.add(10, 20)); + } + +} +Ví dụ biểu thức Lambda với vòng lặp Foreach +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +package com.gpcoder.Lambda; + +import java.util.Arrays; +import java.util.List; + +public class LambdaExpression4 { + + public static void main(String[] args) { + + List languages = Arrays.asList("Java", "C#", "C++", "PHP", "Javascript"); + + // Using Lambda expression + languages.forEach(n -> System.out.println(n)); + } +} +Ví dụ biểu thức Lambda tạo Thread +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +package com.gpcoder.Lambda; + +public class LambdaExpression5 { + + public static void main(String[] args) { + // Using an anonymous inner class + Runnable r1 = new Runnable() { + public void run() { + System.out.println("Runnable 1"); + } + }; + + // Using Lambda Expression for Funcational Interface + Runnable r2 = () -> System.out.println("Runnable 2"); + + r1.run(); + r2.run(); + } +} +Ví dụ biểu thức Lambda với Filter Collection Data +Ví dụ hiển thị danh sách sản phẩm có giá 20000. + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +package com.gpcoder.lambda; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +class Product { +int id; +String name; +float price; + + public Product(int id, String name, float price) { + super(); + this.id = id; + this.name = name; + this.price = price; + } +} + +public class LambdaExpression6 { + + public static void main(String[] args) { + + List list = new ArrayList<>(); + list.add(new Product(1, "Samsung A5", 17000f)); + list.add(new Product(3, "Iphone 6S", 65000f)); + list.add(new Product(2, "Sony Xperia", 25000f)); + list.add(new Product(4, "Nokia Lumia", 15000f)); + list.add(new Product(5, "Redmi4 ", 26000f)); + list.add(new Product(6, "Lenevo Vibe", 19000f)); + + // using lambda to filter data + Stream filtered_data = list.stream().filter(p -> p.price > 20000); + + // using lambda to iterate through collection + filtered_data.forEach(product -> System.out.println(product.name + ": " + product.price)); + } +} +Kết quả thực thi chương trình: + +1 +2 +3 +Iphone 6S: 65000.0 +Sony Xperia: 25000.0 +Redmi4 : 26000.0 +Phạm vi truy cập trong biểu thức Lambda +Việc truy cập các biến phạm vi bên ngoài từ các biểu thức lambda rất giống với các đối tượng ẩn danh (anonymous objects). Bạn có thể truy cập bất kỳ biến final, static hoặc biến chỉ được gán một lần. Biểu thức Lambda throw một lỗi biên dịch, nếu một biến được gán một giá trị lần thứ hai. + +Truy cập biến local – Accessing local variables +Chúng ta có thể truy cập các biến final và biến chỉ được gán một lần. + +Ví dụ: + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +package com.gpcoder.Lambda; + +@FunctionalInterface +interface Converter { +T convert(F from); +} + +public class Java8Scope1 { + + public static void doSomething1() { + final int num = 1; + Converter stringConverter = (from) -> String.valueOf(from + num); + + stringConverter.convert(2); // 3 + } + + public static void doSomething2() { + int num = 1; + Converter stringConverter = (from) -> String.valueOf(from + num); + + stringConverter.convert(2); // 3 + } + + public static void doSomething3() { + int num = 1; + Converter stringConverter = (from) -> String.valueOf(from + num); + + stringConverter.convert(2); // 3 + + // Lambda expression will throw error at num varialbe. + // Local variable num defined in an enclosing scope must be final or effectively + // num = 3; + } + +} +Truy cập Accessing fields and static variables +Chúng ta có thể truy cập và thay đổi các trường hoặc biến static. + +Ví dụ: + +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +package com.gpcoder.Lambda; + +public class Java8Scope2 { + + static int outerStaticNum; + int outerNum; + + void testScopes() { + Converter stringConverter1 = (from) -> { + outerNum = 1; + return String.valueOf(from); + }; + + Converter stringConverter2 = (from) -> { + outerStaticNum = 1; + return String.valueOf(from); + }; + } + +} +Truy cập với phương thức mặc định trong Interface – Accessing Default Interface Methods +Phương thức mặc định (Default methods) không thể truy cập bên trong Biểu thức Lambda. + +Tài liệu tham khảo: + +https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html +https://www.javatpoint.com/java-lambda-expressions +https://www.ntu.edu.sg/home/ehchua/programming/java/JDK8_NewFeatures.html +4.9 +12 +Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! \ No newline at end of file diff --git a/Java-Lambda/readme.md b/Java-Lambda/readme.md index ba0637d..72f03c5 100644 --- a/Java-Lambda/readme.md +++ b/Java-Lambda/readme.md @@ -1,6 +1,9 @@ ## Hướng dẫn thực hành với Lambda + + + ### Java Lambda Expressions parameter -> expression (parameter1, parameter2) -> expression @@ -130,3 +133,7 @@ ### Refactoring Design Pattern với tính năng mới trong java 8 +### Tài liệu tham khảo: + +[Biểu thức Lambda trong Java 8](https://gpcoder.com/3898-bieu-thuc-lambda-trong-java-8-lambda-expressions/) + diff --git a/Java-Lambda/src/core/gpcoder/SortJava8Example.java b/Java-Lambda/src/core/gpcoder/SortJava8Example.java index feca13a..b955507 100644 --- a/Java-Lambda/src/core/gpcoder/SortJava8Example.java +++ b/Java-Lambda/src/core/gpcoder/SortJava8Example.java @@ -1,4 +1,24 @@ package core.gpcoder; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + public class SortJava8Example { + public static void main(String[] args) { + List languages = Arrays.asList("a", "b", "c", "t", "m"); + + Collections.sort(languages, new Comparator() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); + + for (String language : languages){ + System.out.print(language + ", "); + } + + } } diff --git a/Java-Lambda/src/core/gpcoder/SortJava8LambdaExample.java b/Java-Lambda/src/core/gpcoder/SortJava8LambdaExample.java index 075348f..031e0f3 100644 --- a/Java-Lambda/src/core/gpcoder/SortJava8LambdaExample.java +++ b/Java-Lambda/src/core/gpcoder/SortJava8LambdaExample.java @@ -1,2 +1,29 @@ -package core.gpcoder;public class SortJava8LambdaExample { +package core.gpcoder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SortJava8LambdaExample { + public static void main(String[] args) { + System.out.println("Using Lambda Expression"); + List languages = Arrays.asList("a", "b", "c", "t", "m"); + + /** + * Có nghĩa là nó định nghĩa ra một hàm ẩn danh: + * No name + * Có danh sách tham số truyền vào như thường + * Body: xử lý biểu thức hoặc câu lệnh + * No return type: Không có kiểu giá trị trả về tường minh. + * Trình biên dịch Java 8 tự có thể duy luận ra kiểu dữ liệu khi code chạy + */ + Collections.sort(languages, (String o1, String o2) -> { + return o1.compareTo(o2); // Đối với 1 khối lệnh có thể bỏ {} + }); + + for (String language : languages){ + System.out.print(language + ", "); + } + + } } From 6f8c9e196be172e4a863e255a9a9f3bd513a5de1 Mon Sep 17 00:00:00 2001 From: ManhKM Date: Tue, 18 Jul 2023 14:07:09 +0700 Subject: [PATCH 6/8] Refactor Docker Spring Boot --- .../java/com/core/DateVsCalendarDemo.java | 2 + Java-String/src/com/format/StringFormat.java | 7 + Java-Upcasting-Downcasting/readme.md | 0 .../java/com/downcasting/Downcasting.java | 7 + .../src/main/java/com/entity/Animal.java | 7 + .../src/main/java/com/entity/Cat.java | 7 + .../main/java/com/upcasting/Upcasting.java | 7 + .../src/main/java/com/core/Operation.java | 7 + .../src/main/java/com/core/Operation2.java | 7 + demo/.gitignore | 33 ++ demo/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 59925 bytes demo/.mvn/wrapper/maven-wrapper.properties | 18 + demo/Dockerfile | 14 + demo/DockerfileBK | 13 + demo/mvnw | 316 ++++++++++++++++++ demo/mvnw.cmd | 188 +++++++++++ demo/pom.xml | 41 +++ demo/src/main/java/com/core/Application.java | 14 + .../com/core/controller/HomeController.java | 51 +++ .../src/main/java/com/core/entity/Person.java | 84 +++++ .../src/main/resources/application.properties | 4 + .../test/java/com/core/ApplicationTests.java | 13 + demo/volume/data.txt | 13 + 23 files changed, 853 insertions(+) create mode 100644 Java-DateTime/src/main/java/com/core/DateVsCalendarDemo.java create mode 100644 Java-String/src/com/format/StringFormat.java create mode 100644 Java-Upcasting-Downcasting/readme.md create mode 100644 Java-Upcasting-Downcasting/src/main/java/com/downcasting/Downcasting.java create mode 100644 Java-Upcasting-Downcasting/src/main/java/com/entity/Animal.java create mode 100644 Java-Upcasting-Downcasting/src/main/java/com/entity/Cat.java create mode 100644 Java-Upcasting-Downcasting/src/main/java/com/upcasting/Upcasting.java create mode 100644 Java-Variable/src/main/java/com/core/Operation.java create mode 100644 Java-Variable/src/main/java/com/core/Operation2.java create mode 100644 demo/.gitignore create mode 100644 demo/.mvn/wrapper/maven-wrapper.jar create mode 100644 demo/.mvn/wrapper/maven-wrapper.properties create mode 100644 demo/Dockerfile create mode 100644 demo/DockerfileBK create mode 100644 demo/mvnw create mode 100644 demo/mvnw.cmd create mode 100644 demo/pom.xml create mode 100644 demo/src/main/java/com/core/Application.java create mode 100644 demo/src/main/java/com/core/controller/HomeController.java create mode 100644 demo/src/main/java/com/core/entity/Person.java create mode 100644 demo/src/main/resources/application.properties create mode 100644 demo/src/test/java/com/core/ApplicationTests.java create mode 100644 demo/volume/data.txt diff --git a/Java-DateTime/src/main/java/com/core/DateVsCalendarDemo.java b/Java-DateTime/src/main/java/com/core/DateVsCalendarDemo.java new file mode 100644 index 0000000..473a240 --- /dev/null +++ b/Java-DateTime/src/main/java/com/core/DateVsCalendarDemo.java @@ -0,0 +1,2 @@ +package com.core;public class DateVsCalendarDemo { +} diff --git a/Java-String/src/com/format/StringFormat.java b/Java-String/src/com/format/StringFormat.java new file mode 100644 index 0000000..daa8766 --- /dev/null +++ b/Java-String/src/com/format/StringFormat.java @@ -0,0 +1,7 @@ +package com.format;/** + * Project: Java-String (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/14/2023-3:26 PM + * Note: + */public class StringFormat { +} diff --git a/Java-Upcasting-Downcasting/readme.md b/Java-Upcasting-Downcasting/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/Java-Upcasting-Downcasting/src/main/java/com/downcasting/Downcasting.java b/Java-Upcasting-Downcasting/src/main/java/com/downcasting/Downcasting.java new file mode 100644 index 0000000..5b0f224 --- /dev/null +++ b/Java-Upcasting-Downcasting/src/main/java/com/downcasting/Downcasting.java @@ -0,0 +1,7 @@ +package com.downcasting;/** + * Project: Java-Upcasting-Downcasting (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/16/2023-4:01 PM + * Note: + */public class Downcating { +} diff --git a/Java-Upcasting-Downcasting/src/main/java/com/entity/Animal.java b/Java-Upcasting-Downcasting/src/main/java/com/entity/Animal.java new file mode 100644 index 0000000..aa84d98 --- /dev/null +++ b/Java-Upcasting-Downcasting/src/main/java/com/entity/Animal.java @@ -0,0 +1,7 @@ +package com.entity;/** + * Project: Java-Upcasting-Downcasting (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/16/2023-3:52 PM + * Note: + */public class Animal { +} diff --git a/Java-Upcasting-Downcasting/src/main/java/com/entity/Cat.java b/Java-Upcasting-Downcasting/src/main/java/com/entity/Cat.java new file mode 100644 index 0000000..195ba3c --- /dev/null +++ b/Java-Upcasting-Downcasting/src/main/java/com/entity/Cat.java @@ -0,0 +1,7 @@ +package com.entity;/** + * Project: Java-Upcasting-Downcasting (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/16/2023-3:52 PM + * Note: + */public class Cat { +} diff --git a/Java-Upcasting-Downcasting/src/main/java/com/upcasting/Upcasting.java b/Java-Upcasting-Downcasting/src/main/java/com/upcasting/Upcasting.java new file mode 100644 index 0000000..b842077 --- /dev/null +++ b/Java-Upcasting-Downcasting/src/main/java/com/upcasting/Upcasting.java @@ -0,0 +1,7 @@ +package com.upcasting;/** + * Project: Java-Upcasting-Downcasting (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/16/2023-3:52 PM + * Note: + */public class Upcasting { +} diff --git a/Java-Variable/src/main/java/com/core/Operation.java b/Java-Variable/src/main/java/com/core/Operation.java new file mode 100644 index 0000000..adf0b8a --- /dev/null +++ b/Java-Variable/src/main/java/com/core/Operation.java @@ -0,0 +1,7 @@ +package com.core;/** + * Project: Java-Variable (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/14/2023-11:46 AM + * Note: + */public class Operation { +} diff --git a/Java-Variable/src/main/java/com/core/Operation2.java b/Java-Variable/src/main/java/com/core/Operation2.java new file mode 100644 index 0000000..f66a325 --- /dev/null +++ b/Java-Variable/src/main/java/com/core/Operation2.java @@ -0,0 +1,7 @@ +package com.core;/** + * Project: Java-Variable (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/14/2023-11:57 AM + * Note: + */public class Operation2 { +} diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/demo/.mvn/wrapper/maven-wrapper.jar b/demo/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..bf82ff01c6cdae4a1bb754a6e062954d77ac5c11 GIT binary patch literal 59925 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

dy!05UMhSKsK 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 VCNKd3JGtOvEm(5t0lFyE{{i--k}m)N literal 0 HcmV?d00001 diff --git a/demo/.mvn/wrapper/maven-wrapper.properties b/demo/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..ca5ab4b --- /dev/null +++ b/demo/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/demo/Dockerfile b/demo/Dockerfile new file mode 100644 index 0000000..f7c4d95 --- /dev/null +++ b/demo/Dockerfile @@ -0,0 +1,14 @@ +# Stage 1: Xây dựng ứng dụng Spring Boot với Maven +FROM maven:3.8.1-jdk-8 AS build +WORKDIR /app +COPY pom.xml . +RUN mvn dependency:go-offline +COPY src ./src +RUN mvn package + +# Stage 2: Tạo image nhỏ gọn chỉ chứa file .jar đã được đóng gói +FROM adoptopenjdk/openjdk8 +WORKDIR /app +COPY --from=build /app/target/demo-0.0.1-SNAPSHOT.jar /docker-spring-boot.jar +EXPOSE 8099 +CMD ["java", "-jar", "/docker-spring-boot.jar"] \ No newline at end of file diff --git a/demo/DockerfileBK b/demo/DockerfileBK new file mode 100644 index 0000000..9cc16f1 --- /dev/null +++ b/demo/DockerfileBK @@ -0,0 +1,13 @@ +# Sử dụng base image với JDK 1.8.0_202 +FROM adoptopenjdk/openjdk8 + +# Sao chép file .jar từ thư mục target vào image +COPY target/demo-0.0.1-SNAPSHOT.jar /docker-spring-boot.jar + +# Cổng mà ứng dụng lắng nghe +EXPOSE 8099 + +# Lệnh để chạy ứng dụng khi container được khởi chạy +# Mặc định các tham số -Xms, -Xmx sẽ được chỉ định tự đông sao cho tận dụng tối đa tài nguyên của container +# Nếu muốn chỉ định tham số có thể tham khảo: CMD ["java", "-Xms512m", "-Xmx1024m", "-jar", "/app.jar"] +CMD ["java", "-jar", "/docker-spring-boot.jar"] diff --git a/demo/mvnw b/demo/mvnw new file mode 100644 index 0000000..8a8fb22 --- /dev/null +++ b/demo/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/demo/mvnw.cmd b/demo/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/demo/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/demo/pom.xml b/demo/pom.xml new file mode 100644 index 0000000..119693a --- /dev/null +++ b/demo/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.13 + + + com.core + demo + 0.0.1-SNAPSHOT + demo + Demo project for Spring Boot + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/demo/src/main/java/com/core/Application.java b/demo/src/main/java/com/core/Application.java new file mode 100644 index 0000000..dc69b45 --- /dev/null +++ b/demo/src/main/java/com/core/Application.java @@ -0,0 +1,14 @@ +package com.core; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + System.out.println("SERVER IS READY"); + } + +} diff --git a/demo/src/main/java/com/core/controller/HomeController.java b/demo/src/main/java/com/core/controller/HomeController.java new file mode 100644 index 0000000..e70a8c0 --- /dev/null +++ b/demo/src/main/java/com/core/controller/HomeController.java @@ -0,0 +1,51 @@ +package com.core.controller; + +import com.core.entity.Person; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * Project: demo (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/18/2023-11:18 AM + * Note: + */ +@RestController +@RequestMapping("home") +public class HomeController { + + private final Logger logger = LoggerFactory.getLogger(HomeController.class); + + @Value("${app.data.message}") + private String message; + + public static List list = new ArrayList<>(); + + static { + for (int i = 0; i < 999; i++) { + list.add(new Person(Long.valueOf(i), "name_" + i, "address_" + i, i + 18)); + } + } + + @GetMapping() + public List getList() { + logger.info(">>>>> starting method getList()/HomeController....."); + List data = new ArrayList<>(); + for (Person person : list) { + Person _temp = new Person(person.getId(), person.getName(), person.getAddress(), person.getAge(), message); + data.add(_temp); + } + logger.info("Size of Person: " + data.size()); + + logger.info(">>>>> end method getList()/HomeController....."); + + return data; + } +} diff --git a/demo/src/main/java/com/core/entity/Person.java b/demo/src/main/java/com/core/entity/Person.java new file mode 100644 index 0000000..634e15b --- /dev/null +++ b/demo/src/main/java/com/core/entity/Person.java @@ -0,0 +1,84 @@ +package com.core.entity; + +/** + * Project: demo (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/18/2023-11:19 AM + * Note: + */ +public class Person { + private Long id; + private String name; + private String address; + private Integer age; + private String description; + + public Person() { + } + + public Person(Long id, String name, String address, Integer age) { + this.id = id; + this.name = name; + this.address = address; + this.age = age; + } + + public Person(Long id, String name, String address, Integer age, String description) { + this.id = id; + this.name = name; + this.address = address; + this.age = age; + this.description = description; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", address='" + address + '\'' + + ", age=" + age + + ", description='" + description + '\'' + + '}'; + } +} diff --git a/demo/src/main/resources/application.properties b/demo/src/main/resources/application.properties new file mode 100644 index 0000000..41715dc --- /dev/null +++ b/demo/src/main/resources/application.properties @@ -0,0 +1,4 @@ + + +server.port=8099 +app.data.message=Docker with Spring Boot Tutorial \ No newline at end of file diff --git a/demo/src/test/java/com/core/ApplicationTests.java b/demo/src/test/java/com/core/ApplicationTests.java new file mode 100644 index 0000000..1fd60fe --- /dev/null +++ b/demo/src/test/java/com/core/ApplicationTests.java @@ -0,0 +1,13 @@ +package com.core; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/demo/volume/data.txt b/demo/volume/data.txt new file mode 100644 index 0000000..9cc16f1 --- /dev/null +++ b/demo/volume/data.txt @@ -0,0 +1,13 @@ +# Sử dụng base image với JDK 1.8.0_202 +FROM adoptopenjdk/openjdk8 + +# Sao chép file .jar từ thư mục target vào image +COPY target/demo-0.0.1-SNAPSHOT.jar /docker-spring-boot.jar + +# Cổng mà ứng dụng lắng nghe +EXPOSE 8099 + +# Lệnh để chạy ứng dụng khi container được khởi chạy +# Mặc định các tham số -Xms, -Xmx sẽ được chỉ định tự đông sao cho tận dụng tối đa tài nguyên của container +# Nếu muốn chỉ định tham số có thể tham khảo: CMD ["java", "-Xms512m", "-Xmx1024m", "-jar", "/app.jar"] +CMD ["java", "-jar", "/docker-spring-boot.jar"] From 0f22073ccbf4cc2186635579a81a009e6973ed2e Mon Sep 17 00:00:00 2001 From: ManhKM Date: Wed, 19 Jul 2023 15:26:24 +0700 Subject: [PATCH 7/8] Add Checked and UnChecked Exception --- .../TestCheckedExceptionPropagation.java | 35 ++++++++++++++++ .../unchecked/TestExceptionPropagation.java | 40 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 Java-Exception/java-exception/src/com/jindo/core/checked/TestCheckedExceptionPropagation.java create mode 100644 Java-Exception/java-exception/src/com/jindo/core/unchecked/TestExceptionPropagation.java diff --git a/Java-Exception/java-exception/src/com/jindo/core/checked/TestCheckedExceptionPropagation.java b/Java-Exception/java-exception/src/com/jindo/core/checked/TestCheckedExceptionPropagation.java new file mode 100644 index 0000000..d7a7673 --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/checked/TestCheckedExceptionPropagation.java @@ -0,0 +1,35 @@ +package com.jindo.core.checked; + +import java.io.IOException; + +/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-3:22 PM + * Note: Nếu cứ throws mãi mà không ai bắt thì sẽ gây lỗi chương trình + */ +public class TestCheckedExceptionPropagation { + + void m() throws IOException { + // Nếu không bắt Exception mà trả về throws thì n() phải bắt + throw new IOException("Device error/method m()"); + } + + void n() throws IOException { + m(); + } + + void p() { + try { + n(); + } catch (Exception e){ + System.out.println("Exception when execute method m(): " + e.getMessage()); + } + } + + public static void main(String[] args) { + TestCheckedExceptionPropagation obj = new TestCheckedExceptionPropagation(); + obj.p(); + System.out.println("normal flow"); + } +} diff --git a/Java-Exception/java-exception/src/com/jindo/core/unchecked/TestExceptionPropagation.java b/Java-Exception/java-exception/src/com/jindo/core/unchecked/TestExceptionPropagation.java new file mode 100644 index 0000000..0b39865 --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/unchecked/TestExceptionPropagation.java @@ -0,0 +1,40 @@ +package com.jindo.core.unchecked; + +/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-3:17 PM + * Note: Nếu ngoại lệ trong m() không được xử lý, nó sẽ lan truyền đến method n() -> nếu nó cũng không được xử lý nữa thì sẽ lan truyền đến method p() + */ +public class TestExceptionPropagation { + + void m() { + try { + int data = 50 / 0; + } catch (Exception e){ + System.out.println("Exception Handled in m() method"); + } + } + + void n() { + try { + m(); + } catch (Exception e) { + System.out.println("Exception Handled in n() method"); + } + } + + void p() { + try { + n(); + } catch (Exception e) { + System.out.println("Exception Handled in p() method"); + } + } + + public static void main(String[] args) { + TestExceptionPropagation obj = new TestExceptionPropagation(); + obj.p(); + System.out.println("normal flow..."); + } +} From f30260f21ff9ed56bc2e9c26772e89fb4a95c4ac Mon Sep 17 00:00:00 2001 From: ManhKM Date: Wed, 26 Jul 2023 14:22:31 +0700 Subject: [PATCH 8/8] Refactor Dong hoa hoa Thread in Java --- .../core/session3/notification/readme.md | 10 ++++++ .../com/jindo/core/session3/readme.md | 6 ++++ .../multi-thread-tutorial/readme.md | 7 ++++ .../core/session1/basic/BasicThread.java | 30 ++++++++++++++++ .../core/session1/basic/BasicThreadApp.java | 20 +++++++++++ .../exception/ThreadExceptionDemo.java | 4 ++- .../session1/exception/WorkingThread.java | 11 ++++-- .../core/session1/runnable/RunnableDemo.java | 10 +++--- .../session1/thread/ActionInThreadDemo.java | 18 ++++++++++ .../core/session1/thread/ThreadDemo.java | 24 +++++++++++-- .../core/session2/NonDaemonThreadTest2.java | 34 +++++++++++++++++++ .../jindo/core/session2/WorkingThread2.java | 24 +++++++++++++ .../core/session3/block/ShareMemory.java | 2 +- .../core/session3/block/WorkingThread.java | 1 - .../core/session3/method/ShareMemory.java | 13 +++++-- .../core/session3/method/ShareMemoryTest.java | 12 +++++++ .../core/session3/method/WorkingThread.java | 1 - .../core/session3/notification/Customer.java | 13 ++++--- .../core/session3/notification/readme.md | 10 ++++++ .../src/com/jindo/core/session3/readme.md | 6 ++++ .../core/checked/ExceptionChildExample.java | 7 ++++ .../src/com/jindo/core/checked/Parent.java | 7 ++++ .../CustomExceptionApplication.java | 7 ++++ .../customexception/InvalidAgeException.java | 7 ++++ .../unchecked/ThrowsExceptionExample.java | 7 ++++ .../main/java/com/core/ReadApplication.java | 6 ++++ Java-OOP/java-oop/src/gpcoder/oop/Animal.java | 7 ++++ Java-OOP/java-oop/src/gpcoder/oop/Cat.java | 7 ++++ Java-OOP/java-oop/src/gpcoder/oop/Dog.java | 7 ++++ .../src/gpcoder/oop/OopApplication.java | 7 ++++ Java-OOP/java-oop/src/gpcoder/oop/Zoo.java | 7 ++++ .../ConvertObjectToXmlApplication.java | 6 ++++ .../src/com/convertobjectoxml/Person.java | 6 ++++ .../com/convertobjectoxml/WebPageReader.java | 6 ++++ .../com/convertobjectoxml/XmlConverter.java | 6 ++++ .../src/com/convertobjectoxml/XmlField.java | 6 ++++ .../src/com/gpcoder/reflect/Animal.java | 17 +++------- .../reflect/FieldMethodAnnotationExample.java | 6 ++++ .../reflect/JavaReflectionApplication.java | 6 ++++ .../src/com/gpcoder/reflect/Student.java | 6 ++++ 40 files changed, 366 insertions(+), 31 deletions(-) create mode 100644 Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/notification/readme.md create mode 100644 Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/readme.md create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThread.java create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThreadApp.java create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ActionInThreadDemo.java create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/NonDaemonThreadTest2.java create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/WorkingThread2.java create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/readme.md create mode 100644 Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/readme.md create mode 100644 Java-Exception/java-exception/src/com/jindo/core/checked/ExceptionChildExample.java create mode 100644 Java-Exception/java-exception/src/com/jindo/core/checked/Parent.java create mode 100644 Java-Exception/java-exception/src/com/jindo/core/customexception/CustomExceptionApplication.java create mode 100644 Java-Exception/java-exception/src/com/jindo/core/customexception/InvalidAgeException.java create mode 100644 Java-Exception/java-exception/src/com/jindo/core/unchecked/ThrowsExceptionExample.java create mode 100644 Java-Network/java-read-page/src/main/java/com/core/ReadApplication.java create mode 100644 Java-OOP/java-oop/src/gpcoder/oop/Animal.java create mode 100644 Java-OOP/java-oop/src/gpcoder/oop/Cat.java create mode 100644 Java-OOP/java-oop/src/gpcoder/oop/Dog.java create mode 100644 Java-OOP/java-oop/src/gpcoder/oop/OopApplication.java create mode 100644 Java-OOP/java-oop/src/gpcoder/oop/Zoo.java create mode 100644 Java-Reflection/src/com/convertobjectoxml/ConvertObjectToXmlApplication.java create mode 100644 Java-Reflection/src/com/convertobjectoxml/Person.java create mode 100644 Java-Reflection/src/com/convertobjectoxml/WebPageReader.java create mode 100644 Java-Reflection/src/com/convertobjectoxml/XmlConverter.java create mode 100644 Java-Reflection/src/com/convertobjectoxml/XmlField.java create mode 100644 Java-Reflection/src/com/gpcoder/reflect/FieldMethodAnnotationExample.java create mode 100644 Java-Reflection/src/com/gpcoder/reflect/JavaReflectionApplication.java create mode 100644 Java-Reflection/src/com/gpcoder/reflect/Student.java diff --git a/Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/notification/readme.md b/Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/notification/readme.md new file mode 100644 index 0000000..e112f66 --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/notification/readme.md @@ -0,0 +1,10 @@ +## Sử dụng với bài toán Notification trong bài toán đa luồng. + +### Bài toán + +Nếu trong quá trình luồng 1 khóa đối tượng Resource b, sau khi thực hiện được 1 đoạn công việc, luồng 1 cần luồng 2 làm việc số việc gì đó trên resource B này. + +Sau khi đó mới có điều kiện để luồng 1 thực hiện tiếp logic -> lúc này mới có đủ dữ liệu để làm tiếp. + +wait(), notify(), notifyall() + diff --git a/Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/readme.md b/Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/readme.md new file mode 100644 index 0000000..2e1eccf --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/out/production/multi-thread-tutorial/com/jindo/core/session3/readme.md @@ -0,0 +1,6 @@ +## Đồng bộ luồng trong Java + +Đồng bộ hóa (synchronized) chính là việc xắp xếp thứ tự các luồng khi truy xuất vào cùng đối tượng sao cho nó không có sự xung đột dữ liệu. + +Đồng bộ hóa = thứ tự hóa + diff --git a/Java-Concurrence/multi-thread-tutorial/readme.md b/Java-Concurrence/multi-thread-tutorial/readme.md index 4820e08..92abbfb 100644 --- a/Java-Concurrence/multi-thread-tutorial/readme.md +++ b/Java-Concurrence/multi-thread-tutorial/readme.md @@ -1,3 +1,10 @@ +## Tổ chức package trong dự án + +session1: Thực hiện tạo một Thread từ Runnable, khi đó sử dụng Thread này trong việc Random số liệu + + + + ## Multithreading [Multi-Thread](https://gpcoder.com/category/java-core/multi-thread/) diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThread.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThread.java new file mode 100644 index 0000000..b4a5286 --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThread.java @@ -0,0 +1,30 @@ +package com.jindo.core.session1.basic; + +/** + * @author ManhKM as [ADMIN] + * @project multi-thread-tutorial on 7/26/2023-11:09 AM (>_<)/ + * @note + */ +public class BasicThread extends Thread { + + private String name; + + public BasicThread(String name) { + this.name = name; + } + + /** + * Định nghĩa sự kiện thực thi của Thread + */ + @Override + public void run() { + for (int i = 10; i > 0; i--) { + System.out.println(name + '-' + i); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThreadApp.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThreadApp.java new file mode 100644 index 0000000..6379a66 --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/basic/BasicThreadApp.java @@ -0,0 +1,20 @@ +package com.jindo.core.session1.basic; + +/** + * @author ManhKM as [ADMIN] + * @project multi-thread-tutorial on 7/26/2023-11:12 AM (>_<)/ + * @note + */ +public class BasicThreadApp { + public static void main(String[] args) { + + BasicThread basicThreadA = new BasicThread("thread-a"); + BasicThread basicThreadB = new BasicThread("thread-b"); + BasicThread basicThreadC = new BasicThread("thread-c"); + BasicThread basicThreadD = new BasicThread("thread-d"); + + basicThreadA.start(); + basicThreadB.start(); + + } +} diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/ThreadExceptionDemo.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/ThreadExceptionDemo.java index b223ca0..fedffeb 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/ThreadExceptionDemo.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/ThreadExceptionDemo.java @@ -11,7 +11,9 @@ public static void main(String[] args) { Thread thread = new Thread(new WorkingThread()); - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){ + thread.setDaemon(false); + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/WorkingThread.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/WorkingThread.java index 3829474..388f24c 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/WorkingThread.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/exception/WorkingThread.java @@ -5,6 +5,7 @@ /** * @author ManhKM on 3/8/2023 * @project multi-thread-tutorial + * @note Thực hành tạo một Thread implement Runnable */ public class WorkingThread implements Runnable { @@ -15,10 +16,16 @@ public void run() { } } + /** + * Thực hiện nghiệm vụ chính trong hệ thống + * Thực hiện random một số trong khoảng + * Nếu nó rơi vào một case chỉ định thì dừng chương trình + * Nếu có exception sảy ra trong quá trình chạy thì quit + */ private void processSomething() { Random random = new Random(); - int i = random.nextInt(200); + int i = random.nextInt(9_000); try { System.out.println("[" + i + "] Processing working thread"); Thread.sleep(10); @@ -27,7 +34,7 @@ private void processSomething() { } if (i == 70) { - throw new RuntimeException("Giá trị này = 70, không xủ lý trong Thread"); + throw new RuntimeException("Giá trị này = 70, không xử lý trong Thread"); } } } diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/runnable/RunnableDemo.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/runnable/RunnableDemo.java index 31806c7..7f95f2d 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/runnable/RunnableDemo.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/runnable/RunnableDemo.java @@ -4,12 +4,12 @@ * @author ManhKM on 3/8/2023 * @project multi-thread-tutorial */ -public class RunnableDemo implements Runnable{ +public class RunnableDemo implements Runnable { private Thread t; private String threadName; - RunnableDemo(String threadName){ + RunnableDemo(String threadName) { this.threadName = threadName; System.out.println("Creating " + threadName); } @@ -19,7 +19,7 @@ public void run() { System.out.println("Creating " + threadName + " ..."); try { - for (int i = 1000; i > 0; i--){ + for (int i = 1000; i > 0; i--) { System.out.println("Thread: " + threadName + ", " + i); Thread.sleep(100); } @@ -28,9 +28,9 @@ public void run() { } } - public void start(){ + public void start() { System.out.println("Starting " + threadName); - if(t == null){ + if (t == null) { t = new Thread(this, threadName); t.start(); } diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ActionInThreadDemo.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ActionInThreadDemo.java new file mode 100644 index 0000000..23156e5 --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ActionInThreadDemo.java @@ -0,0 +1,18 @@ +package com.jindo.core.session1.thread; + +/** + * @author ManhKM as [ADMIN] + * @project multi-thread-tutorial on 7/26/2023-11:04 AM (>_<)/ + * @note + */ +public class ActionInThreadDemo { + public static void main(String[] args) { + + // Khởi tạo một Thread: + ThreadDemo threadDemo1 = new ThreadDemo("new-thread-01"); // NEW +// threadDemo1.start(); // RUNNABLE + threadDemo1.stop(); + threadDemo1.interrupt(); + threadDemo1.resume(); + } +} diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ThreadDemo.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ThreadDemo.java index cfdcac8..e34dc60 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ThreadDemo.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session1/thread/ThreadDemo.java @@ -3,30 +3,45 @@ /** * @author ManhKM on 3/8/2023 * @project multi-thread-tutorial + * @note: Tạo một Thread cơ bản từ việc kế thừa Thread */ public class ThreadDemo extends Thread { private Thread t; private String threadName; + /** + * Vừa setting tên và thực hiện gán cho nó một Thread + * @param t + * @param name + */ ThreadDemo(Thread t, String name){ this.t = t; this.threadName = name; System.out.println("Creating " + threadName + ", Thread " + t.getName()); } + /** + * Constructor thực hiện khởi tọa đối tượng ThreadDemo + * và setting giá trị name cho nó + * @param name + */ ThreadDemo(String name) { this.threadName = name; System.out.println("Creating " + threadName); } + /** + * Nơi định nghĩa các kịch bản chạy của Thread này + * Thực hiện chạy thread với N lần quy định, mỗi lần chạy nghỉ M giây + */ @Override public void run() { System.out.println("Running " + threadName); try { - for (int i = 4; i > 0; i--) { + for (int i = 10; i > 0; i--) { System.out.println("Thread " + threadName + ", " + i); - Thread.sleep(50); + Thread.sleep(2000); } } catch (InterruptedException e) { System.err.println("Thread: " + threadName + " interrupted."); @@ -34,6 +49,11 @@ public void run() { System.out.println("Thread " + threadName + " exiting..."); } + /** + * Hàm bắt đầu custom của chương trình + * Client sẽ gọi hàm này -> nó sẽ gọi hàm start của thread + * Từ đó cấp phát tài nguyên và bắt đầu -> run() của thread + */ public void start() { System.out.println("Starting " + threadName); if (t == null) { diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/NonDaemonThreadTest2.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/NonDaemonThreadTest2.java new file mode 100644 index 0000000..bbe7e8a --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/NonDaemonThreadTest2.java @@ -0,0 +1,34 @@ +package com.jindo.core.session2; + +/** + * @author ManhKM as [ADMIN] + * @project multi-thread-tutorial on 7/26/2023-11:36 AM (>_<)/ + * @note + */ +public class NonDaemonThreadTest2 { + public static void main(String[] args) { + Thread dt = new Thread(new WorkingThread2(), "My Non-Daemon Thread 2"); + + dt.setDaemon(false); + dt.start(); + + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Thread dt2 = new Thread(new WorkingThread2(), "My Daemon Thread 2"); + + dt2.setDaemon(true); + dt2.start(); + + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println(">><< Finishing main program"); + } +} diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/WorkingThread2.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/WorkingThread2.java new file mode 100644 index 0000000..3d1f081 --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session2/WorkingThread2.java @@ -0,0 +1,24 @@ +package com.jindo.core.session2; + +/** + * @author ManhKM as [ADMIN] + * @project multi-thread-tutorial on 7/26/2023-11:34 AM (>_<)/ + * @note Thực hiện một luồng cơ bản + */ +public class WorkingThread2 implements Runnable { + @Override + public void run() { + while (true) { + processSomething(); + } + } + + private void processSomething() { + try { + System.out.println("Processing working thread"); + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/ShareMemory.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/ShareMemory.java index f22a241..3bd89f5 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/ShareMemory.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/ShareMemory.java @@ -7,7 +7,7 @@ public class ShareMemory { //synchronized - public void printData(String threadName) { + public synchronized void printData(String threadName) { synchronized (this) { for (int i = 1; i <= 20; i++) { System.out.println(threadName + ": " + i); diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/WorkingThread.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/WorkingThread.java index f987a8e..c61fa6d 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/WorkingThread.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/block/WorkingThread.java @@ -6,7 +6,6 @@ */ public class WorkingThread extends Thread { - private Thread thread; private ShareMemory shareMemory; private String threadName; diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemory.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemory.java index 175a835..7a2d663 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemory.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemory.java @@ -6,10 +6,19 @@ */ public class ShareMemory { - //synchronized + // Xác định index in ra ngoài màn hình + volatile int count = 0; + + /** + * synchronized + * Cơ chế: Phương thức này sẽ được cấp duy nhất 1 java monitor + * Chỉ có luồng nào nắm giữ monitor mới có quyền gọi phương thức này + * @param threadName + */ public synchronized void printData(String threadName){ for (int i = 1; i <= 20; i++){ - System.out.println(threadName + ": " + i); + count++; + System.out.println(threadName + ": " + i + "\t - [count]: " + count); } } } diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemoryTest.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemoryTest.java index 5cb655d..fdbd2fc 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemoryTest.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/ShareMemoryTest.java @@ -8,16 +8,28 @@ public class ShareMemoryTest { public static void main(String[] args) { + System.out.println("Synchronized methods: "); + ShareMemory shareMemory = new ShareMemory(); WorkingThread thread1 = new WorkingThread(shareMemory, "Thread-01"); WorkingThread thread2 = new WorkingThread(shareMemory, "Thread-02"); WorkingThread thread3 = new WorkingThread(shareMemory, "Thread-03"); WorkingThread thread4 = new WorkingThread(shareMemory, "Thread-04"); + WorkingThread thread5 = new WorkingThread(shareMemory, "Thread-05"); + WorkingThread thread6 = new WorkingThread(shareMemory, "Thread-06"); + WorkingThread thread7 = new WorkingThread(shareMemory, "Thread-07"); + WorkingThread thread8 = new WorkingThread(shareMemory, "Thread-08"); thread1.start(); thread2.start(); thread3.start(); thread4.start(); + thread5.start(); + thread6.start(); + thread7.start(); + thread8.start(); + + System.out.println("THE END APPLICATION...."); } } diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/WorkingThread.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/WorkingThread.java index c60f9af..85c7578 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/WorkingThread.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/method/WorkingThread.java @@ -6,7 +6,6 @@ */ public class WorkingThread extends Thread { - private Thread thread; private ShareMemory shareMemory; private String threadName; diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/Customer.java b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/Customer.java index 49f7af7..03afd8b 100644 --- a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/Customer.java +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/Customer.java @@ -8,13 +8,18 @@ public class Customer { private int balance = 1000; - public Customer(){ + public Customer() { System.out.println("Tài khoản của bạn là: " + balance); } - public synchronized void withdraw(int amount){ + /** + * Thực hiện giao dịch rút tiền + * + * @param amount + */ + public synchronized void withdraw(int amount) { System.out.println("Đang thực hiện giao dịch rút tiền " + amount + " ..."); - while (balance < amount){ + while (balance < amount) { System.out.println("Không đủ số tiền trong tài khoản để rút, số dư hiện tại là: " + this.balance); try { wait(); // Chờ đến khi nạp đủ tiền @@ -27,7 +32,7 @@ public synchronized void withdraw(int amount){ System.out.println("Rút tiền thành công. Tài khoản hiện tại là: " + balance); } - public synchronized void deposit(int amount){ + public synchronized void deposit(int amount) { System.out.println("Đang thực hiện giao dịch nạp tiền " + amount + " ..."); balance += amount; System.out.println("Nạp tiền thành công. Tài khoản hiện tại của bạn là: " + balance); diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/readme.md b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/readme.md new file mode 100644 index 0000000..e112f66 --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/notification/readme.md @@ -0,0 +1,10 @@ +## Sử dụng với bài toán Notification trong bài toán đa luồng. + +### Bài toán + +Nếu trong quá trình luồng 1 khóa đối tượng Resource b, sau khi thực hiện được 1 đoạn công việc, luồng 1 cần luồng 2 làm việc số việc gì đó trên resource B này. + +Sau khi đó mới có điều kiện để luồng 1 thực hiện tiếp logic -> lúc này mới có đủ dữ liệu để làm tiếp. + +wait(), notify(), notifyall() + diff --git a/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/readme.md b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/readme.md new file mode 100644 index 0000000..2e1eccf --- /dev/null +++ b/Java-Concurrence/multi-thread-tutorial/src/com/jindo/core/session3/readme.md @@ -0,0 +1,6 @@ +## Đồng bộ luồng trong Java + +Đồng bộ hóa (synchronized) chính là việc xắp xếp thứ tự các luồng khi truy xuất vào cùng đối tượng sao cho nó không có sự xung đột dữ liệu. + +Đồng bộ hóa = thứ tự hóa + diff --git a/Java-Exception/java-exception/src/com/jindo/core/checked/ExceptionChildExample.java b/Java-Exception/java-exception/src/com/jindo/core/checked/ExceptionChildExample.java new file mode 100644 index 0000000..636e833 --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/checked/ExceptionChildExample.java @@ -0,0 +1,7 @@ +package com.jindo.core.checked;/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/20/2023-6:31 AM + * Note: + */public class ExceptionChildExample { +} diff --git a/Java-Exception/java-exception/src/com/jindo/core/checked/Parent.java b/Java-Exception/java-exception/src/com/jindo/core/checked/Parent.java new file mode 100644 index 0000000..4a272fb --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/checked/Parent.java @@ -0,0 +1,7 @@ +package com.jindo.core.checked;/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/20/2023-6:29 AM + * Note: + */public class Parent { +} diff --git a/Java-Exception/java-exception/src/com/jindo/core/customexception/CustomExceptionApplication.java b/Java-Exception/java-exception/src/com/jindo/core/customexception/CustomExceptionApplication.java new file mode 100644 index 0000000..b73137e --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/customexception/CustomExceptionApplication.java @@ -0,0 +1,7 @@ +package com.jindo.core.customexception;/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/20/2023-6:19 AM + * Note: + */public class CustomExceptionApplication { +} diff --git a/Java-Exception/java-exception/src/com/jindo/core/customexception/InvalidAgeException.java b/Java-Exception/java-exception/src/com/jindo/core/customexception/InvalidAgeException.java new file mode 100644 index 0000000..16521b6 --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/customexception/InvalidAgeException.java @@ -0,0 +1,7 @@ +package com.jindo.core.customexception;/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/20/2023-6:18 AM + * Note: + */public class InvalidAgeException { +} diff --git a/Java-Exception/java-exception/src/com/jindo/core/unchecked/ThrowsExceptionExample.java b/Java-Exception/java-exception/src/com/jindo/core/unchecked/ThrowsExceptionExample.java new file mode 100644 index 0000000..2fc8a0e --- /dev/null +++ b/Java-Exception/java-exception/src/com/jindo/core/unchecked/ThrowsExceptionExample.java @@ -0,0 +1,7 @@ +package com.jindo.core.unchecked;/** + * Project: java-exception (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-3:27 PM + * Note: + */public class ThrowsExceptionExample { +} diff --git a/Java-Network/java-read-page/src/main/java/com/core/ReadApplication.java b/Java-Network/java-read-page/src/main/java/com/core/ReadApplication.java new file mode 100644 index 0000000..bac50d9 --- /dev/null +++ b/Java-Network/java-read-page/src/main/java/com/core/ReadApplication.java @@ -0,0 +1,6 @@ +package com.core;/** + * @project java-read-page on 7/24/2023-10:30 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class ReadApplication { +} diff --git a/Java-OOP/java-oop/src/gpcoder/oop/Animal.java b/Java-OOP/java-oop/src/gpcoder/oop/Animal.java new file mode 100644 index 0000000..d3569bf --- /dev/null +++ b/Java-OOP/java-oop/src/gpcoder/oop/Animal.java @@ -0,0 +1,7 @@ +package gpcoder.oop;/** + * Project: java-oop (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-10:21 PM + * Note: + */public class Animal { +} diff --git a/Java-OOP/java-oop/src/gpcoder/oop/Cat.java b/Java-OOP/java-oop/src/gpcoder/oop/Cat.java new file mode 100644 index 0000000..cce83c8 --- /dev/null +++ b/Java-OOP/java-oop/src/gpcoder/oop/Cat.java @@ -0,0 +1,7 @@ +package gpcoder.oop;/** + * Project: java-oop (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-10:23 PM + * Note: + */public class Cat { +} diff --git a/Java-OOP/java-oop/src/gpcoder/oop/Dog.java b/Java-OOP/java-oop/src/gpcoder/oop/Dog.java new file mode 100644 index 0000000..a4fa833 --- /dev/null +++ b/Java-OOP/java-oop/src/gpcoder/oop/Dog.java @@ -0,0 +1,7 @@ +package gpcoder.oop;/** + * Project: java-oop (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-10:25 PM + * Note: + */public class Dog { +} diff --git a/Java-OOP/java-oop/src/gpcoder/oop/OopApplication.java b/Java-OOP/java-oop/src/gpcoder/oop/OopApplication.java new file mode 100644 index 0000000..e3083f0 --- /dev/null +++ b/Java-OOP/java-oop/src/gpcoder/oop/OopApplication.java @@ -0,0 +1,7 @@ +package gpcoder.oop;/** + * Project: java-oop (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-10:27 PM + * Note: + */public class OopApplication { +} diff --git a/Java-OOP/java-oop/src/gpcoder/oop/Zoo.java b/Java-OOP/java-oop/src/gpcoder/oop/Zoo.java new file mode 100644 index 0000000..1a789e4 --- /dev/null +++ b/Java-OOP/java-oop/src/gpcoder/oop/Zoo.java @@ -0,0 +1,7 @@ +package gpcoder.oop;/** + * Project: java-oop (>_<)/ + * Author: ManhKM as [ADMIN] + * Date-Time: 7/19/2023-10:25 PM + * Note: + */public class Zoo { +} diff --git a/Java-Reflection/src/com/convertobjectoxml/ConvertObjectToXmlApplication.java b/Java-Reflection/src/com/convertobjectoxml/ConvertObjectToXmlApplication.java new file mode 100644 index 0000000..f5c3e7f --- /dev/null +++ b/Java-Reflection/src/com/convertobjectoxml/ConvertObjectToXmlApplication.java @@ -0,0 +1,6 @@ +package com.convertobjectoxml;/** + * @project Java-Reflection on 7/24/2023-10:21 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class ConvertObjectToXmlApplication { +} diff --git a/Java-Reflection/src/com/convertobjectoxml/Person.java b/Java-Reflection/src/com/convertobjectoxml/Person.java new file mode 100644 index 0000000..d050e91 --- /dev/null +++ b/Java-Reflection/src/com/convertobjectoxml/Person.java @@ -0,0 +1,6 @@ +package com.convertobjectoxml;/** + * @project Java-Reflection on 7/24/2023-10:20 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class Person { +} diff --git a/Java-Reflection/src/com/convertobjectoxml/WebPageReader.java b/Java-Reflection/src/com/convertobjectoxml/WebPageReader.java new file mode 100644 index 0000000..d387798 --- /dev/null +++ b/Java-Reflection/src/com/convertobjectoxml/WebPageReader.java @@ -0,0 +1,6 @@ +package com.convertobjectoxml;/** + * @project Java-Reflection on 7/24/2023-10:26 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class WebPageReader { +} diff --git a/Java-Reflection/src/com/convertobjectoxml/XmlConverter.java b/Java-Reflection/src/com/convertobjectoxml/XmlConverter.java new file mode 100644 index 0000000..1e29129 --- /dev/null +++ b/Java-Reflection/src/com/convertobjectoxml/XmlConverter.java @@ -0,0 +1,6 @@ +package com.convertobjectoxml;/** + * @project Java-Reflection on 7/24/2023-10:17 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class XmlConverter { +} diff --git a/Java-Reflection/src/com/convertobjectoxml/XmlField.java b/Java-Reflection/src/com/convertobjectoxml/XmlField.java new file mode 100644 index 0000000..600f488 --- /dev/null +++ b/Java-Reflection/src/com/convertobjectoxml/XmlField.java @@ -0,0 +1,6 @@ +package com.convertobjectoxml;/** + * @project Java-Reflection on 7/24/2023-10:15 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class XmlField { +} diff --git a/Java-Reflection/src/com/gpcoder/reflect/Animal.java b/Java-Reflection/src/com/gpcoder/reflect/Animal.java index 5f437b9..be3bea8 100644 --- a/Java-Reflection/src/com/gpcoder/reflect/Animal.java +++ b/Java-Reflection/src/com/gpcoder/reflect/Animal.java @@ -1,13 +1,6 @@ -package com.gpcoder.reflect; - -/** - * @author ManhKM on 10/19/2022 - * @project Java-Reflection - */ -public abstract class Animal { - public String getLocation(){ - return "VietNam"; - } - - public abstract int getNumberOfLegs(); +package com.gpcoder.reflect;/** + * @project Java-Reflection on 7/24/2023-12:12 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class Animal { } diff --git a/Java-Reflection/src/com/gpcoder/reflect/FieldMethodAnnotationExample.java b/Java-Reflection/src/com/gpcoder/reflect/FieldMethodAnnotationExample.java new file mode 100644 index 0000000..f0f58d5 --- /dev/null +++ b/Java-Reflection/src/com/gpcoder/reflect/FieldMethodAnnotationExample.java @@ -0,0 +1,6 @@ +package com.gpcoder.reflect;/** + * @project Java-Reflection on 7/24/2023-1:38 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class FieldMethodAnnotationExample { +} diff --git a/Java-Reflection/src/com/gpcoder/reflect/JavaReflectionApplication.java b/Java-Reflection/src/com/gpcoder/reflect/JavaReflectionApplication.java new file mode 100644 index 0000000..888bf70 --- /dev/null +++ b/Java-Reflection/src/com/gpcoder/reflect/JavaReflectionApplication.java @@ -0,0 +1,6 @@ +package com.gpcoder.reflect;/** + * @project Java-Reflection on 7/24/2023-1:45 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class JavaReflectionApplication { +} diff --git a/Java-Reflection/src/com/gpcoder/reflect/Student.java b/Java-Reflection/src/com/gpcoder/reflect/Student.java new file mode 100644 index 0000000..8cacfef --- /dev/null +++ b/Java-Reflection/src/com/gpcoder/reflect/Student.java @@ -0,0 +1,6 @@ +package com.gpcoder.reflect;/** + * @project Java-Reflection on 7/24/2023-1:46 PM (>_<)/ + * @author ManhKM as [ADMIN] + * @note + */public class Student { +}