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