---
# System prepended metadata

title: Java

---

# Java

open jdk: 
1. https://jdk.java.net/archive/
2. https://www.openlogic.com/openjdk-downloads?field_java_parent_version_target_id=406&field_operating_system_target_id=436&field_architecture_target_id=391&field_java_package_target_id=All

war檔解壓縮
```java
jar -xvf xxx.war
```
maven打包並省略測試指令 & 啟動:
```java
mvn clean package -DskipTests && java -jar target/xxx.jar
```
Android: https://hackmd.io/@cmrdb/H10TzG3pd/%2F%40cmrdb%2FH1xHD5qRd

### POJO(Plain Old Java Object):
最簡單純粹的Java物件，滿足以下條件:
-必須定義預設建構子
-必須有唯一識別屬性(ID)，對應主鍵
-最好設計為JAVA Bean
-屬性修飾字private
-要有getter/setter

**VO(Value Object，值物件)**
存活於業務層，主要用於業務層之間的資料傳遞，僅僅包含自身的資料，以new關鍵字建立，由GC回收
**DTO(Data Transfer Object，資料傳輸物件)**
類似VO，主要用於需要大量傳輸資料，跟VO比較不同的地方是在傳輸時只傳輸需要的屬性(或額外添加的屬性)，可以減少資料傳遞的量及避免table結構暴露
**PO(persistant object，持久層物件)** 
因ORM而有的概念，存活在一個DB連線中，斷開連線即摧毀，主要應用於數據的持久化，
必須實現序列化Serializable
**DAO(data access object，資料訪問物件)**
是為某種類型的資料庫或其他永續性機制提供一個抽象介面的物件，通過對映應用程式對持久層的呼叫，DAO提供一些特定的資料操作

### 抽象類別/介面
抽象類別裡可以放抽象方法，**也可以放實作方法**
但抽象方法**只能放在抽象類別**裡
繼承抽象類別時，**必須**實作抽象方法
實作介面時，**必須**實作所有方法

### i++ 與 ++i 的差異
i++時: 會先賦值後，執行完該行再將數值i=i+1
++i時: 會直接將數值+1後直接賦值

### Array
Array宣告分為兩種方式，一種是先宣告陣列長度，但不填入值:
```java
//代表一維String陣列，長度4(最大索引值3)
String[] strArr = new String[4]; 

//代表二維int陣列，長度各為5(最大索引值4)、3(最大索引值2)
int[][] intArr = new int[5][3]; 
```
另一種是宣告時直接賦值:
```java
//代表已內含3個值的int陣列
int[] intArr = {1,3,4};
```

### ternary operator
三元運算子用法:
條件 ? true輸出 : false輸出
```java
String s1 = true ? "A" : "B";
System.out.println(s1);  //輸出"A"
String s2 = false ? "A" : "B";
System.out.println(s2);   //輸出"B"
```

### 存取修飾子Access Modifier
private: **自己**可用
default: **package**內可用
protect: **package** + **subclass**
public:  **全部**可用

### Java載入行為順序
1.	static靜態方法(裡面的靜態屬性)
2.	static靜態程式碼區塊( static{…} )
3.	非靜態方法(裡面的屬性)
4.	非靜態程式碼區塊( {…} )
5.	建構子

### 複製兩個Bean參數相同的部分
```java
import org.apache.commons.beanutils.BeanUtils; //springframework有類似的用法，但要注意參數放的位置

BeanUtils.copyProperties(A,B)  //將B中參數的值賦值給A中參數
```

### 類別泛型設計
```java
//在類別中使用泛型，可以預設有一個未知的類別存在此類別中
public class XxxVO<V>{
    ...
    private V oxxVO ;
    ...
    public V getOxxVO() {
		return oxxVO;
    }
    public void setOxxVO(V oxxVO) {
		this.oxxVO = oxxVO;
    }
    ...
}
```
### Proxy代理模式程式設計
```java
import org.apache.commons.beanutils.MethodUtils;
import com.ebao.pub.framework.internal.spring.DSProxy;

Object[] parameters = {...}; //方法需要用到的參數

XxxClass xxx = (XxxClass)MethodUtils.invokeMethod(DSProxy.newInstanceByBeanName("beanName字串"),"方法名稱",parameters);
```

## 日期相關
```java
//指定日期的Date
Date theDate = new GregorianCalendar(1999,9-1,9).getTime();  //GregorianCalendar的月份是由0開始
Date theDate = new GregorianCalendar(1999,Calendar.SEPTEMBER,9).getTime();
```


## 字串相關

### toString()的null問題
```java
Integer i1 = 100;
//NG，有nullPointException風險
String i1ToString = i1.toString();
//better
String s1 = String.valueOf(i1);
```
### String.split()
將字串以特定方式切割成字串陣列
```java
String str = "c,a,t";
String[] splitStr = str.split(",");
for (String s : splitStr){
    System.out.println(s);
}
//印出結果
//c
//a
//t
```
### String.join()
將字串陣列以特定字拼裝
```java
List<String> strList = new ArrayList<String>();
strList.add("c");
strList.add("a");
strList.add("t");
System.out.println(String.join("_", strArr);
//印出結果
//c_a_t
```

### String.getByte() 
將字串轉換為byte陣列的方法(對應結果可參考 https://zh.wikipedia.org/wiki/ASCII )，也可傳入"UTF-8"等編碼格式，否則會使用defalt
```java
String str = "make";
byte[] byt = str.getBytes();
for (byte b : byt) {
    System.out.println(b); 
}
//印出結果
//109
//97
//107
//101
```

## 串流

### Stream.of()
```java
//快速拼裝集合，不需一直add()
List<Integer> numList = Stream.of(1,2,3,4,5).collect(Collectors.toList());
``` 

### stream().filter
```java
//拿到的集合
List<Emp> empListRawData = ...;

//用來收集串流過濾好的集合
List<Emp> empListFilterd 
       = empListRawData.stream()
           //emp為自定義變數，代表當中每一個元素
           //像for-each迴圈一樣  for(emp:empList){...}
           .filter( emp-> emp.age < 30)
           .collect(Collectors.toList());
``` 

### stream().map
```java
//拿到的集合
List<Emp> empListRawData = ...;

//用來收集Emp的name屬性
List<String> empNameList 
    = empListRawData.stream()
    .map(Emp::getEmpName)
    .collect(Collectors.toList());
```

### stream().max / min
```java
List<Integer> list = Arrays.asList(-9, -18, 0, 25, 4);
Integer maxNum = list.stream()
    .max(Integer::compare).get();
```

## 其他

### Optional範例
```java
//如vo.getName為空值時，可以使用預設空字串
XxxVO vo = Optional
    .ofNullable(vo.getName()).orElse("");
```

### retainAll() 快速過濾集合交集
```java
// 兩個集合使用過後，呼叫的集合僅剩與傳入重複的部分
List<Integer> list1 = Stream.of(2,3,4).collect(Collectors.toList());
        List<Integer> list2 = Stream.of(3,4,5).collect(Collectors.toList());
        list1.retainAll(list2);
        System.out.println(list1); // [3, 4]

```

### List比較器
```java
List<String> strList = new ArrayList<String>();
Collections.sort(strList, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        if (condition...) {
            return 1;  
        } else if (condition2...) {
            return 0;
        } else
            return -1;
    }
});
return strList;
```

### Map遍歷
```java
Map<Integer,String> map = new HashMap();
for (Map.Entry<Integer, String> entry : map.entrySet()){
    System.out.println("key=" + entry.getKey() + "value=" + entry.getValue());
}
```

### Map比較器
利用Comparator來對節點進行比較的寫法
```java
//宣告一個HashMap
Map<Integer, String> unsortMap = new HashMap<>();
unsortMap.put(10, "z");
unsortMap.put(5, "b");
unsortMap.put(1, "d");
unsortMap.put(7, "e");

//宣告一個有比較器的TreeMap
Map<Integer, String> treeMap = new TreeMap<>(new Comparator<Integer>() {
    //覆寫比較器
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
});
//將Map丟進去
treeMap.putAll(unsortMap);
for (Map.Entry<Integer, String> entry : treeMap.entrySet()) {
    System.out.print(entry.getValue() + " ");
}
```

### java.util.Date 日期比較
比較兩日期先後
```java
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = dateFormat.parse("2011-05-21");
Date date2 = dateFormat.parse("2015-01-21");
Date date3 =  dateFormat.parse("2011-05-21");

//after(Date date)比較日期先後
boolean isAfter = date2.after(date);
System.out.println("date2 is after date: " + isAfter);

//compare(Date date)比較日期是否相等
System.out.println (date1.compareTo(date3) == 0); //回傳true

```

### 執行續暫時休眠
```java
Thread.currentThread().sleep(1000);
```

### 關於javax.crypto.*
常用於判斷加密簽章，algorithm可傳入演算法參考: https://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA
```java
//用給定的byte陣列及給定的演算法構造一個密鑰
SecretKeySpec key = new SecretKeySpec(byte[] key, String algorithm);

//生成MAC算法的實體(MAC=Message Authentication Code)
Mac mac = Mac.getInstance(String algorithm);

//初始化Mac物件
mac.init(key);


```


### 用來Gen java檔的小程式 
```java

import java.io.File;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 產生 Dao/Service檔的小程式
 * @author Tony Tu
 *
 */
public class DaoServiceGenerator {
	
	// file separator
	private static final String SEPARATOR = File.separator;

	// PACKAGE名稱 FIXME 
	private static String PACKAGE_NAME = "";
	
	// BEAN名稱 FIXME 
	private static String BEAN_NAME = "";

	// 欲產出項目
	private static Boolean GEN_DAO = true;
	private static Boolean GEN_SERVICE = true;

	// 輸出的位置 
	private static String SOURCE_ROOT = "D:" + SEPARATOR ;

	public static void main(String[] args) throws Exception{
		
		generate(BEAN_NAME, PACKAGE_NAME);
	
	}
	
	private static void generate(String beanName, String packageName)
			throws ResourceNotFoundException, ParseErrorException, Exception {
		
		//創建日期
		String createTime = DateTimeFormatter
				.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH)
				.format(LocalDateTime.now());
		
		String lowerBeanName = StringUtils.substring(beanName, 0, 1).toLowerCase() + StringUtils.substring(beanName, 1);
		String daoClassName = beanName + "Dao";
		String serviceClassName = beanName + "Service";
		String serviceImplClassName = serviceClassName + "Impl";
		
		
		DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document doc = builder.parse(SOURCE_ROOT + beanName + ".mmd.xml");
		NodeList nList = doc.getElementsByTagName("id");
		Node node = nList.item(0);
		String idVarStr = ((Element)node).getAttribute("name");
		String[] idPackAndType = ((Element)node).getAttribute("type").split("\\.");
		String idTypeStr = idPackAndType[idPackAndType.length - 1];
		
		Velocity.init();
		VelocityContext velocityContent = new VelocityContext();
		velocityContent.put("packageName", packageName);
		velocityContent.put("daoClassName", daoClassName);
		velocityContent.put("serviceClassName",serviceClassName);
		velocityContent.put("serviceImplClassName",serviceImplClassName);
		velocityContent.put("beanName", beanName);
		velocityContent.put("lowerBeanName", lowerBeanName);
		velocityContent.put("idVarStr",idVarStr);
		velocityContent.put("idTypeStr",idTypeStr);
		velocityContent.put("createTime", createTime.toString());

		if (GEN_DAO){
			output("DaoGenerator.vm",daoClassName,velocityContent);
		}
		
		if (GEN_SERVICE) {
			output("ServiceGenerator.vm",serviceClassName,velocityContent);
			output("ServiceImplGenerator.vm", serviceImplClassName, velocityContent);			
		}

	}
	
	public static void output(String template, String className, VelocityContext velocityContent) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception{
		StringWriter stringWriter = new StringWriter();
		Velocity.getTemplate(template).merge(velocityContent, stringWriter);
		
		String targetPath = SOURCE_ROOT + className + ".java";
		FileUtils.writeStringToFile(new File(targetPath), stringWriter.toString(),"UTF-8");
		
	}

}


```


