2022/06/19 (連結更新)
2024/06/26 (更新內容)
2024/07/11 (更新內容)
2024/08/06 (更新內容)
2024/08/07 (更新內容)
一般而言,一個基本的java程式一定會有個main():
package com.example.demo;
public class DemoApplication {
public static void main(String[] args) {
}
}
跟其他語言(如:python、php)不同,java程式一定要是個類別,以範例程式為例,類別名稱是DemoApplication,而且這個檔案也必須儲存為DemoApplication.java。
public class DemoApplication {
}
跟其他語言(如:python、php)不同,執行java程式不是同第一行開始執行,而是執行main。
public class DemoApplication {
public static void main(String[] args) {
}
}
java一開始的設計就已經是認定輸出、輸入會是多元化,所以,如果要在螢幕上輸出,就要採用System.out.println。System.out.println接受一個字串參數,並將字串顯示在螢幕上。
public class DemoApplication {
public static void main(String[] args) {
System.out.println("Hello");
}
}
java是強資料型態的語言,一方面,在使用變數之前, 一定要先定義,另一方面,也必須定義變數的資料型態,以一個整數變數為例,「int」表示是一個整數變數,「qty」是變數名稱,另外,也可以利用「=」指定起始值 ,跟php很像,結尾要有「;」:
int qty = 0;
細節請詳參Java Variables
跟很多語言一樣,可以利用「=」改變內容,唯一不同的是,不能改變資料型態,也不能使用未定義變數。
qty = qty + 1;
qty = "0"; //語法錯誤
q = qty + 1; //語法錯誤
跟很多語言一樣(其實都來自於c語言)當然也可以利用「++」讓變數加一寫成:
qty++;
細節請詳參Java Operators
在java裡,定義一個常數,使用的關鍵字是「final」,而不是「const」
final int qty = 0;
qty ++; //語法錯誤
在java裡,定義在大括號裡的變數,在大括號外面就不認得了。
{
int qty = 0;
System.out.println(qty);
}
System.out.println(qty);//語法錯誤
java跟php很像,有if、switch、while、for等基本語法。
陣列的語法跟php有點類似,要注意的是,java指定陣列起始值使用的是大括號,另外,也要先指定陣列裡所有元素的資料型態。
int[] myNum = {10, 20, 30, 40};
System.out.println(myNum[0]);
java也有類似php的foreach,只是,語法長的不太一樣:
for (int num : myNum) {
System.out.println(num);
}
Java裡沒有php的Associative array,不過,有類似的資料結構,如:Java HashMap 。
一般而言,通常不會直接使用一個類別,而是先產生物件,透過物件去呼叫方法,而且去取得這物件裡的變數,而通常會稱這些變數為物件的屬性 (attributes/properties)。
假設有一個類別: Product,裡面有name及price兩個變數:
public class Product {
private String name;//屬性
private int price;
}
定義一些方法(通常稱為getters及setters)去取得或更動屬性,這樣的好處是可以加入檢查的邏輯,避免有不合理的屬性內容 (例如:負值的價格)。
public class Product {
//屬性
private String name;
private int price;
//方法
public String getName() {
return name;
}
public int getPrice() {
return price;
}
public void setName(String name) {
this.name = name;
}
public void setPrice(int price) {
if (price >= 0) {
this.price = price;
}
else {
this.price = 0;
}
}
}
我們就可以從Product類別產生物件,所有的物件的屬性是獨立的。
Product a = new Product();
Product b = new Product();
a.setName("iPhone");
a.setPrice("10000");
b.setName("iPad");
b.setPrice("12000");
Java Classes and Objects (W3School)
Java Class Attributes (W3School)
Java Class Methods (W3School)
Defining Classes (Wikibooks)
Object (吳濟聰老師線上課程)
在java裡,所有的函數都必須屬於類別,稱之為方法。在java裡的方法,要定義回傳值的資料型態,如果沒有回傳值,則使用void。
public void myPublicMethod() {
System.out.println("Public methods must be called by creating objects");
}
方法有兩種,一種是類別方法 (static method)
// Static method
public static void myStaticMethod() {
System.out.println("Static methods can be called without creating objects");
}
public static void main(String[] args) {
}
一種是物件方法
// Object method
public void myPublicMethod() {
System.out.println("Public methods must be called by creating objects");
}
使用物件方法,一定要先產生物件。
Main myObj = new Main(); // Create an object of Main
myObj.myPublicMethod(); // Call the public method on the object
php裡也有類別與物件,只是較少人使用。然而,在java裡類別與物件卻是必備的核心概念。
public class Main {
// Static method
public static void myStaticMethod() {
System.out.println("Static methods can be called without creating objects");
}
// Object method
public void myPublicMethod() {
System.out.println("Public methods must be called by creating objects");
}
// Main method
public static void main(String[] args) {
myStaticMethod(); // Call the static method
// myPublicMethod(); This would compile an error
Main myObj = new Main(); // Create an object of Main
myObj.myPublicMethod(); // Call the public method on the object
}
}
Design Objects and Classes (吳濟聰老師線上課程)
類別中含有其他類別是Java最常見的語法,例如,我們有個EmployeeController類別,這類別裡用到一個Employee類別,這時候,為了讓使用EmployeeController的類別可以取得employee的內容,就提供一個get(),讓其他類別可以取得資料。
public class EmployeeController {
private employee = new Employee(1, "Arpit", "IT");
public Employee get() {
return employee;
}
}
假如我們不是只有一個Employee,而是多個,我們可以將Employee放在ArrayList裡:
public class EmployeeController {
private ArrayList<Employee> employeeList = new ArrayList<>();
public EmployeeController(){
employeeList.add(new Employee("Arpit", "IT"));
employeeList.add(new Employee("Sanjeev", "IT"));
employeeList.add(new Employee("Ben", "IT"));
}
public ArrayList<Employee> get() {
return employeeList;
}
}
Complex Classes (composition) (吳濟聰老師線上課程)
真實的使用情境如下: (完整程式請參考:Spring Rest Controller)
package com.example.demo.controller;
import java.util.ArrayList;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.Employee;
@RestController
public class EmployeeController {
private ArrayList<Employee> employeeList = new ArrayList<>();
public EmployeeController(){
employeeList.add(new Employee("Arpit", "IT"));
employeeList.add(new Employee("Sanjeev", "IT"));
employeeList.add(new Employee("Ben", "IT"));
}
@GetMapping("/employee")
public ArrayList<Employee> get() {
return employeeList;
}
}
Composition與Inheritance是物件導向裡最重要的兩個概念,這兩個概念都可以重複利用程式碼,例如上面的EmployeeController就重複利用Employee裡的程式碼。接下來介紹另一種使用方式:Inheritance。
public class Employee{
private String name;
public Employee() {
}
public Employee(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
假如我們有兩種Employee: FullTimeEmployee及PartTimeEmployee,我們可以繼承Employee,可以重複利用Employee裡的程式碼。
public class FullTimeEmployee extends Employee{
private int salary; //月薪
public FullTimeEmployee() {
super();
}
public FullTimeEmployee(final String name, final int salary) {
super(name);
this.salary = salary;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
由於PartTimeEmployee是以時薪計算,所以,算薪資的時候,需要這個月的工作時數
public class PartTimeEmployee extends Employee{
private int salary; //時薪
public PartTimeEmployee() {
super();
}
public PartTimeEmployee(final String name, final int salary) {
super(name);
this.salary = salary;
}
public int getSalary() {
return salary * 20 * 8;//應該要取的每月工作時數,先簡化計算邏輯
}
public void setSalary(int salary) {
this.salary = salary;
}
}
Inheritance (只有投影片、原始影片已遺失) (吳濟聰老師線上課程)
在物件導向程式語言中,提供了一個很有用的語法,那就是Polymorphism,這也是物件導向中很重要的一個概念,什麼是polymorphism呢? 我們來舉個例子:
public class TestPolymorphism{
private ArrayList<Employee> employeeList = new ArrayList<>();
public TestPolymorphism(){
employeeList.add(new FullTimeEmployee("Arpit", 30000));
employeeList.add(new PartTimeEmployee("Sanjeev", 300));
employeeList.add(new PartTimeEmployee("Ben", 250));
}
public void printNames() {
for (Employee e : employeeList){
System.out.println(e.getName());
}
}
}
第一、可以在Employee類別的ArrayList中加入FullTimeEmployee或PartTimeEmployee
employeeList.add(new FullTimeEmployee("Arpit", 30000));
employeeList.add(new PartTimeEmployee("Sanjeev", 300));
employeeList.add(new PartTimeEmployee("Ben", 250));
第二、使用的時候,不用管裡面的物件是哪個類別,這樣的效果就是同名異式polymorphisim,但是,我們可能會說,其實在這兩個類別中本來就沒有getName(),本來就是呼叫Employee裡的getName()。等到介紹Abstract及Interface時,同名異式才更有趣。
for (Employee e : employeeList){
System.out.println(e.getName());
}
Polymorphism (吳濟聰老師線上課程)
如果呼叫getSalary(),就會有問題,因為在編譯的時候會出現語法錯誤,因為編譯時,編譯器認為這是個Employee的物件,找不到getSalary()。
for (Employee e : employeeList){
System.out.println(e.getSalary());
}
為了要解決這個問題,物件導向語言提供了一個abstract的概念,也就是可以讓super class去要求sub class必須要寫這些方法abstract方法,這樣子的話,當編譯時,一方面找不到方法的問題就消失了,另一方面,當編譯FullTimeEmployee及PartTimeEmployee時,編譯器也會要求我們一定要寫這兩個方法。
public abstract class Employee{
private String name;
public Employee() {
}
public Employee(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract int getSalary();
public abstract void setSalary(int salary);
}
Abstract Classes and Interface (吳濟聰老師線上課程)
在java裡,並沒有多重繼承。然而,如果使用的都是abstract方法時,實作多個abstract方法其實是沒問題,而且,往往是需要的,所以,在java裡就提供了interface。簡單的說,一個interface就是所有方法都是abstract method的類別,只是我們稱之為interface,因為這樣的類別通常是拿來定義API介面。在spring裡,到處可以看到interface的身影。
例如,在SpringDB裡,為了不讓將來的改變影響整個系統,通常會增加一個interface (CustomerDAO) ,在Controller裡就使用CustomerDAO而不是CustomerDAOImpl,到時候,如果CustomerDAOImpl必須更換時,就不需要改Controller的內容了。
src\main\java\com\example\demo\dao\CustomerDAO.java
package com.example.demo.dao;
import java.util.List;
import com.example.demo.entity.Customer;
public interface CustomerDAO {
public List<Customer> findAll();
}
然後,我們再寫一個類別,並實作這個interface:
public class CustomerDAOImpl implements CustomerDAO {
public List<Customer> findAll() {
}
}
完整的程式碼:
package com.example.demo.dao;
import java.util.ArrayList;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.Customer;
@Repository
public class CustomerDAOImpl implements CustomerDAO {
@Autowired
private DataSource dataSource;
//jdbc
public List<Customer> findAll() {
List<Customer> customers = new ArrayList<Customer>();
try {
Connection conn = dataSource.getConnection();
String sql = "select id, name, address, weight from customer";
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
while (rs.next()){
customers.add(getCustomer(rs));
}
conn.close();
} catch(Exception e) {
//something wrong
System.out.println(e);
}
return customers;
}
public Customer getCustomer(ResultSet rs) throws SQLException{
return new Customer(
rs.getLong("id"),
rs.getString("name"),
rs.getString("address"),
rs.getInt("weight"));
}
}
Abstract Classes and Interface (吳濟聰老師線上課程)
@在java中稱為Annotation,Annotation是java 5的新語法,雖然很多人將Annotation翻譯為註解,但是,Annotation跟Comment是完全不一樣的,Comment是純粹給人看的,而Annotation卻是給Compiler看的。
Annotations in Java (2022)
Java annotation (wikipedia)
Spring大量的使用Annotation,例如,一開始就使用到@SpringBootApplication,告訴java compiler,這不是一個普通的java類別,而是一個SpringBootApplication,會去啟動內建的Tomcat伺服器,並且執行這個類別。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
在RestController裡也可以看到:
package com.example.demo.controller;
import java.util.ArrayList;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.Employee;
@RestController
public class EmployeeController {
private ArrayList<Employee> employeeList = new ArrayList<>();
public EmployeeController(){
employeeList.add(new Employee("Arpit", "IT"));
employeeList.add(new Employee("Sanjeev", "IT"));
employeeList.add(new Employee("Ben", "IT"));
}
@GetMapping("/employee")
public ArrayList<Employee> get() {
return employeeList;
}
}
java 5.0之後的語法: 泛型(Generic)
泛型在現在的Java程式中到處可見,例如,ArrayList。由於內建的陣列必須要是先定義長度,所以,後來Java提供了ArrayList類別,為了可以定義ArrayList裡每一個物件的資料型態,我們就透過泛型去定義,例如,我們定義這個ArrayList裡的每個物件都是Employee類別:
private ArrayList<Employee> employeeList = new ArrayList<>();
在JDBCTemplate裡將下面的程式:
public List<Customer> findAll() {
return this.jdbcTemplate.query( "select id, name, address, weight from customer", new CustomerMapper());
}
private static final class CustomerMapper implements RowMapper<Customer> {
public Customer mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Customer(
rs.getLong("id"),
rs.getString("name"),
rs.getString("address"),
rs.getInt("weight")
);
}
}
利用lambda語法,簡化成:
public List<Customer> findAll() {
return this.jdbcTemplate.query( "select id, name, address, weight from customer",
(rs, rowNum) -> new Customer(
rs.getLong("id"),
rs.getString("name"),
rs.getString("address"),
rs.getInt("weight")
)
);
}
Java Programming (Wikibooks)
要有意義,所以名稱都應該有意義,避免類似「i」、「i」、「firstVariable」等無法代表變數內容的名稱。
類別名: 類別名的第一個字一律大寫,如果是由多個字組成,每個字的開頭一律大寫,如:PurchaseOrder。
物件名: 物件名的第一個字一律小寫,如果是由多個字組成,除第一個以外,每個字的開頭一律大寫,如:purchaseOrder。
屬性(變數)名: 屬性的第一個字一律小寫,如果是由多個字組成,除第一個以外,每個字的開頭一律大寫,如:reorderPoint,習慣上不再冠類別名,(如:在Customer裡,不用customerName,而是,name)。
方法名: 方法的第一個字一律小寫,如果是由多個字組成,除第一個以外,每個字的開頭一律大寫,如:getReorderPoint。
4 Things That are most confusing for Java Developer (2019)
Usage of Announymous Classes
Multithreading
Implementation of Synchronization
Serialization
Functional Programming
Please stop the Java Optional mess!
Optional badly done
Use of Optional in Java fields in our classes
Express the optionality of a value in constructors by using Optional
How to handle exceptions properly within streams: the functional way
Java Stream API — Learn how to convert streams to other data structures
String title = switch (person) {
case Dali, Picasso -> "painter";
case Mozart, Prokofiev -> "composer";
case Goethe, Dostoevsky -> "writer";
};
String myMultiLineText = """
first line
second line
""";
How to use the Executor Framework in Java : A Complete Guide for Thread Management with Java Executor — Part 1
How to use Java Callable and Future : A Complete Guide for Thread Management with Java Executor — Part 2
Annotations for Concurrency in Java. Our approach to coloring threads
Java Tutorial (TutorialsPoint)
Lombok makes Java cool again (2019)
What Is Modularity in Java? (2020)
4 Amazing Techniques for Writing Better Java (2020)
Covariant Types (Java 5)
The covariant return type specifies that the return type of the class may vary in the same direction as the subclass.
Intersectional Generic Types
Auto-Closeable Classes
Java 7 introduces the try-with-resources
Final Classes and Methods
10 excellent GitHub repositories for every Java developer (2020)
Java Design Patterns
Interviews
Algorithms
Realworld
Awesome Java
Baeldung Tutorials
JHipster
RxJava Android Samples
Java8 Tutorial
Cracking the Coding Interview in Java
Java version history / Java版本歷史
最新版是Java SE 22 (2024/03),但建議使用 Java SE 21 (2023/9)。
其中有幾個比較重要的版本是屬於Long Term Support (LTS),目前還在維護中,所以,大家盡量使用這些版本。
Java 8
免費維護:RedHat/Eclipse Temurin到2026
Java 11
免費維護:Eclipse Temurin到2027
Java 17
免費維護:RedHat/Eclipse Temurin到2027
Java 21
免費維護:RedHat/Eclipse Temurin到2029
Java SE 5 is the most significant release (2017)
SE5
Generic data structures
For-each loop
Auto-boxing/unboxing
Variadic methods (varargs)
Return type covariance
Annotations
Enumerations
Standard library
Static imports
SE6
Standard library
SE7
Generic diamond operator
Try-with-resources statement
Numeric literal syntax
Switch on strings
Multi-catch
Standard library: Various utilities
SE8
Better generic type inference
Capture of effectively final variables
Standard library
Interface default methods
JAVA 8與JAVA 11到底該怎麼選? (2020)
變量類型推斷 (Java 10)
官方HTTP Client加持
String處理增強
集合增強
函數式編程增強
文件讀寫增強
支持源文件直接運行
從Java 11到Java 17 (2021)
A New Future for Java (based on Java 14) (2020)
History of JVM Languages
Java
Groovy
Scala
Clojure
Kotlin
The “Kotlinisation” of Java
Java records
Improved switch statement
Text blocks
Java 17 language compared to Java 8. How modern Java is better than Java 8? (2021)
Encapsulation
Modules (Java 9)
Sealed types (Java 15)
Code brevity
Local Variable Type Inference (Java 10)
Switch Expressions (Java 12)
Text blocks (Java 13)
Records (Java 14)
Type casting
Pattern Matching for instanceof (Java 14)
Pattern matching in switch (Java 17)
New Features by Baeldung
New Features in Java 8 ** LTS
New Features in Java 11 **LTS
New Features in Java 17 **LTS
Java 18 (no new features for developers)
Java 19 new features are in preview
New Features in Java 21 **LTS