Giải pháp chuyển đổi số trọn gói cho doanh nghiệp Việt
Mình xin giải thích một chút ý nghĩa của bài hôm nay. Bài học hôm nay đáng lý ra phải nằm ở bài 9 – Bài nói về các câu lệnh lặp – Vì kiến thức của bài hôm nay có liên quan các câu lệnh lặp đó. Tuy nhiên mình nghĩ nếu nói về kiến thức này ở bài trước sẽ làm cho bài học bị dài ra, vừa khó để các bạn nhớ, vừa khó để thực hành, lại khó cho mình khi phải viết một bài quá dài. Chính vì vậy mình tách ra thành một bài học hôm nay.
Chúng ta sẽ nói đến 2 câu lệnh nhảy trong bài hôm nay, đó là break và continue. Trong khi có một câu lệnh nhảy khác là return sẽ được trao đổi ở bài viết về Phương Thức sau nhé.
Sở dĩ Java dùng từ “nhảy” không phải vì nó làm cho các vòng lặp của bạn thêm nhảy nhót. Nhảy ở đây là nhảy ra khỏi vòng lặp, hay nhảy đến một lần lặp tiếp theo, bỏ qua các câu lệnh còn lại bên trong thân vòng lặp đó. Một số tài liệu khác gọi đây là các câu lệnh điều khiển, nhưng mình thích từ nhảy hơn, tiếng Việt nghe hơi chuối nhưng tiếng Anh họ gọi là jump statements, nghe rõ nghĩa hơn.
Chúng ta cùng xem qua nhé.
Bạn hiểu nghĩa break là đập vỡ cũng đúng, nhưng trong tình huống này nó có nghĩa là dừng thì hay hơn.
Theo đúng tên gọi, khi câu lệnh này xuất hiện ở đâu đó trong vòng lặp, chúng sẽ làm phá vỡ, hay dừng vòng lặp đó dù cho vẫn còn các câu lệnh khác bên trong vòng lặp chưa được xử lý.
Nếu bạn còn nhớ, ở bài 8 chúng ta cùng nói qua câu lệnh break này cho cấu trúc switch case đúng không nào. Vâng, break ở switch case và break ở câu lệnh lặp cũng có công dụng tương tự như nhau thôi.
Bài thực hành này muốn bạn in ra console tất cả các số nguyên tố từ 1 đến 10.000.
Khoan! Có gì đó sai sai! In số nguyên tố đã được thực hành ở bài trước rồi mà! Và in số nguyên tố thì có liên quan gì đến break!?!
Bạn yên tâm, in số nguyên tố ở bài trước chỉ là một giải thuật “gà”. Trong lập trình, đặc biệt là lập trình các thuật toán, sẽ luôn luôn hoan nghênh các bạn có những giải thuật cải tiến sao cho ứng dụng chạy nhanh, mượt. Muốn được như vậy thì các thuật toán của các bạn phải gọn, bắt máy tính làm việc ít hơn, số lượng vòng lặp giảm thiểu,… Có lẽ chúng ta sẽ nói đến chủ đề này ở bài khác.
Quay lại bài thực hành, chúng ta sẽ cải tiến giải thuật tìm số nguyên tố, kết hợp với câu lệnh break để dừng việc kiểm tra sớm một khi đã biết số đó không phải là số nguyên tố.
Bạn đã biết số nguyên tố là số chỉ chia hết cho 1 và chính nó. Để làm vậy, với cách cũ bạn duyệt qua các số hạng từ 1 đến chính nó, đếm xem có bao nhiêu số hạng mà nó chia hết cho, nếu đếm thấy 2 số hạng thì nó đúng là số nguyên tố. Với cách này bạn luôn phải cho vòng lặp chạy hết tất cả các số hạng. Cụ thể, với việc kiểm tra số 10.000, thì ứng dụng của bạn sẽ phải lặp 10.000 lần để đếm. Cách này mình đo thấy ứng dụng tốn 376 ms (mili giây) để chạy, tức là gần nửa giây. Bạn có thể áp dụng break vào việc giảm số lần lặp bằng 2 cách sau.
Mình áp dụng cách chạy nhanh nhất trên đây vào code bên dưới, bạn áp dụng cách nào? Hãy thử code nhé.
Lại một lần nữa nghĩa và công dụng của từ này bị lẫn lộn. Bạn giỏi tiếng Anh nên hiểu nghĩa của continue là tiếp tục cũng không sai, nhưng tình huống này chúng ta hiểu là bỏ qua.
Khác với dừng trên kia – Dừng là dừng luôn không quay lại nó nữa – Còn bỏ qua có nghĩa là bỏ các câu lệnh còn lại bên trong vòng lặp để thực hiện một chu trình lặp mới. Câu lệnh này không làm dừng vòng lặp như break, mà chỉ thực hiện vòng lặp mới, nhưng vòng lặp cũng có thể bị dừng bởi continue khi mà việc thực hiện vòng lặp mới sẽ kiểm tra và thấy điều_kiện_lặp không còn thỏa.
Có một lưu ý nhỏ khi bạn dùng continue cho for và while/do while như sau.
Bài này bạn sẽ phải in ra console ngược lại với bài thực hành ở trên, kết hợp với continue. Bạn hãy viết chương trình in ra console tất cả các số KHÔNG PHẢI LÀ SỐ NGUYÊN TỐ trong khoảng từ 1 đến 100.
Chúng ta sẽ áp dụng giải thuật tìm số nguyên tố, hễ biết đó là số nguyên tố thì sẽ dùng continue “lướt” qua lần lặp mới, các câu lệnh in ra console sẽ để bên dưới câu lệnh continue để đảm bảo in ra những gì không thỏa điều kiện của continue. Code chúng ta như sau.
Mục này mình mới thêm vào sau này, ở giai đoạn đầu tiên của bài viết mình không nói đến việc gán nhãn cho vòng lặp. Tại sao mình lại bỏ qua nó? Thứ nhất bạn nên hiểu rằng Java gần như đã bỏ khái niệm goto của C++. Với kiến thức về goto thì bạn có thêm một tùy chọn cho việc điều khiển luồng trong ứng dụng, nó cho phép bạn rẽ nhánh xử lý đến bất kỳ nơi nào bạn chỉ định. Điều này gây vô số khó khăn trong việc kiểm soát luồng chạy của ứng dụng, rất khó để tìm kiếm và gỡ lỗi nếu có. Nên với Java, ít có nơi nào nói kỹ nên gần như chúng ta quên mất khái niệm goto này. Thứ hai, nếu không biết gì về kiến thức goto chúng ta vẫn xây dựng hoàn chỉnh các ứng dụng mong muốn.
Tuy nhiên với một vài tình huống nhất định, nhất là khi sử dụng các vòng lặp lồng vào nhau, có khi bạn mong muốn được dừng hay bỏ qua vòng lặp con để về một vòng lặp bên ngoài bất kỳ, khi đó goto phát huy tác dụng. Java hỗ trợ cho chúng ta kỹ thuật này cho tình huống này, nó được gọi là label, gán nhãn cho vòng lặp, giúp bạn gán một nhãn bất kỳ cho vòng lặp, sau đó break hay continue sẽ được chỉ định để dừng hoặc bỏ qua vòng lặp hiện tại để về đúng nhãn mà bạn đã gán.
Bạn hãy nhìn kỹ cách sử dụng nhãn ở bài thực hành dưới đây. Mình dùng nhãn chung với lệnh continue, nhưng bạn hoàn toàn có thể hiểu và áp dụng tương tự với break. Trong trường hợp bạn còn mông lung về việc gán nhãn và sử dụng nhãn, thì mình khuyên bạn không nên có gắng dùng nó mà làm chi nhé.
Bài này chúng ta lại tiếp tục cải tiến cho việc in ra console tất cả các số nguyên tố từ 1 đến 10.000 mà Bài Thực Hành Số 1 trên kia dường như làm khá tốt rồi.
Ý tưởng của Bài Thực Hành Số 1 là cứ mỗi số cần kiểm tra (ở vòng lặp ngoài cùng), cờ isPrime sẽ được khai báo lại là true rồi vào vòng lặp bên trong sẽ xác định và set cờ isPrime là false hay không. Ra khỏi vòng lặp con mà isPrime vẫn còn là true thì sẽ in số đó ra vì nó chính là số nguyên tố.
Bài thực hành này chúng ta không cần dùng đến cờ isPrime luôn, mà ở vòng lặp trong, nếu biết đó là số nguyên tố, lệnh continue kết hợp với nhãn sẽ dẫn luồng xử lý về lại vòng lặp for được gán nhãn. Mời bạn xem code và gác diễn giải ngay trong code.
Nếu bạn muốn biết việc so sánh thời gian xử lý, thì Bài Thực Hành Số 1 cũng đã là một giải thuật quá hay rồi, nên bài thực hành này cũng chỉ giúp giảm thời gian thêm một chút xíu thôi, cụ thể mình đo và thấy thời gian xử lý của bài này là 10 ms.
Chưa có câu hỏi nào cho bài này.