# 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");
}
}
```