Total Pageviews

2016/10/31

[Travel] 2016/10

行天宮
IMG_5478

松山文創園區
IMG_5483

南子吝山
DSC00812

DSC00809

DSC00800

2016/10/10

[Java 8] Using lambda to convert a List of object to comma-separated string

If I java an object which named Group
1
2
3
4
5
6
7
    import lombok.Data;
    
    @Data
    public class Group {    
        private Integer id;
        private String name;
    }

The data in List of Group looks like:
1
2
3
    Group(id=1, name=Group A)
    Group(id=2, name=Group B)
    Group(id=3, name=Group C)

The expected result is to convert to comma-separated string: 
Group A, Group B, Group c

If we does not utilize lambda expression, the code snippet is as following:
1
2
3
4
5
6
7
8
9
    List<Group> groups = dto.getUser().getGroups();
    StringBuilder groupStringBuilder = new StringBuilder();
    for (int i = 0; i < groups.size(); i++) {
        if (i == groups.size() - 1) {
            groupStringBuilder = groupStringBuilder.append(groups.get(i).getName());
        } else {
            groupStringBuilder = groupStringBuilder.append(groups.get(i).getName()).append(", ");
        }
    }


If we apply lambda expression, we only need to use one line of code to meet this requirement:
    String groupStr = groups.stream().map(g -> g.getName()).collect(Collectors.joining(", "));




2016/10/09

[Java 8] Convert a List of String to a Comma-Separated String

If I have a List of String looks like:
1
2
3
private List<String> getDummyPlayers() {
    return Arrays.asList("王 柏 融", "林 智 勝", "林 泓 育", "蔣 智 賢", "高 國 慶");
}

If I would like to convert it to String, and each player should separate with comma, i.e. 王 柏 融, 林 智 勝, 林 泓 育, 蔣 智 賢, 高 國 慶

Before Java 8, we may do this way:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
private String separatePlayersWithComma(){
    List<String> players =getDummyPlayers();
    String playersWithComma = "";
    for (int i = 0; i < players.size(); i++) {
        if (i == players.size() - 1) {
            playersWithComma = playersWithComma + players.get(i);
        } else {
            playersWithComma = playersWithComma + players.get(i) +", "; 
        }
    }
    return playersWithComma;
}


In Java 8, it is very easy and straightforward:
1
2
3
4
5
private String separatePlayersWithComma_usingJDK8(){
    List<String> players =getDummyPlayers();
    String playersWithComma = players.stream().collect(Collectors.joining(", "));
    return playersWithComma;
}






2016/10/08

[Project Lombok] @Cleanup

Project Lombok provide an easy way to ensure a given resource is automatically cleaned up before the code execution path exits your current scope. All you need to do is to annotate any local variable declaration with the @Cleanup annotation.


As-Is (Do not annotate @Cleanup)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
private void readExcelTest1(String excelFile) throws IOException {
     List<Issue> issues = new ArrayList<Issue>();

     InputStream inputStream = null;
     Workbook workbook = null;

     try {
         // 1. Create a Workbook.
         inputStream = new FileInputStream(new File(excelFile));

         // 2. Get first sheet
         workbook = new HSSFWorkbook(inputStream);

         Sheet sheet = workbook.getSheetAt(0);

         // 3. Iterate through each rows from first sheet
         Iterator<Row> rowIterator = sheet.iterator();
         int rowCount = 1;
         while (rowIterator.hasNext()) {
            // (1) ignore header row
            if (rowCount == 1) {
              rowIterator.next();
              rowCount++;
             }
             // (2) start to read each row from second row
             else {
                 Row row = rowIterator.next();
                 Integer id = Double.valueOf(row.getCell(0).getNumericCellValue()).intValue();
                 String subject = row.getCell(1).getStringCellValue();
                 String status = row.getCell(2).getStringCellValue();
                 String priority = row.getCell(3).getStringCellValue();
                 String notes = row.getCell(4).getStringCellValue();

                 Issue issue = new Issue();
                 issue.setId(id);
                 issue.setSubject(subject);
                 issue.setStatus(status);
                 issue.setPriority(priority);
                 issue.setNotes(notes);

                 issues.add(issue);
              }
           }

          // print collection
          issues.stream().forEach(issue -> log.debug(issue.toString()));
     } catch (FileNotFoundException e) {
         throw e;
     } catch (IOException e) {
         throw e;
     } finally {
         if (workbook != null) {
           workbook.close();
         }

         if (inputStream != null) {
           inputStream.close();
         }
     }
}



To-Be(Annotte with @Cleanup)
It will ensure the variable declaration that you annotate will be cleaned up by calling its close method, regardless of what happens. Implemented by wrapping all statements following the local variable declaration to the end of your scope into a try block that, as a finally action, closes the resource. 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 private void readExcelTest2(String excelFile) throws Exception {
     try {
         // 1. Create a Workbook.
         @Cleanup
         InputStream inputStream = new FileInputStream(new File(excelFile));

         // 2. Get first sheet
         @Cleanup
         Workbook workbook = new HSSFWorkbook(inputStream);

         List<Issue> issues = new ArrayList<Issue>();

         Sheet sheet = workbook.getSheetAt(0);
 
         // 3. Iterate through each rows from first sheet
         Iterator<Row> rowIterator = sheet.iterator();
         int rowCount = 1;
         while (rowIterator.hasNext()) {
              // (1) ignore header row
              if (rowCount == 1) {
              rowIterator.next();
              rowCount++;
              }
              // (2) start to read each row from second row
              else {
                  Row row = rowIterator.next();
                  Integer id = Double.valueOf(row.getCell(0).getNumericCellValue()).intValue();
                  String subject = row.getCell(1).getStringCellValue();
                  String status = row.getCell(2).getStringCellValue();
                  String priority = row.getCell(3).getStringCellValue();
                  String notes = row.getCell(4).getStringCellValue();

                  Issue issue = new Issue();
                  issue.setId(id);
                  issue.setSubject(subject);
                  issue.setStatus(status);
                  issue.setPriority(priority);
                  issue.setNotes(notes);
    
                  issues.add(issue);
              }
         }

         // print collection
         issues.stream().forEach(issue -> log.debug(issue.toString()));
    
     } catch (FileNotFoundException e) {
         throw e;
     } catch (Exception e) {
         throw e;
     }
 }



Reference
[1] https://projectlombok.org/features/Cleanup.html

2016/10/07

[PDFBox] Generate TIF with 0-kb

Problem
I am using Apache PDFBox to convert PDF to TIF file.

The scenario is to generate TIF file to a specific path, then another application will read this TIF file and move to another directory.



But it will generate TIF file with 0-kb at times and fail to open this TIF file, and does not have any abnormal message in application log.


How-To

Here is the code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    private List<String> writeImage(PDDocument document, String outputPrefix, ImageType imageType,
            float dpi, String fileName) throws IOException {
        ImageIO.scanForPlugins();

        List<String> tifNames = new ArrayList<String>();

        PDFRenderer renderer = new PDFRenderer(document);

        for (int i = 0; i < document.getNumberOfPages(); i++) {

            BufferedImage image = renderer.renderImageWithDPI(i, dpi, imageType);

            String outputPostfix = "_" + String.format("%02d", i + 1); // 01開始
            String outputFileName = outputPrefix + outputPostfix;// 檔名: 保單號碼_0X

            tifNames.add(fileName + outputPostfix); // 回傳產了那些檔名

            ImageIOUtil.writeImage(image, outputFileName + "." + "tif", Math.round(dpi));
            image.flush();
        }
        return tifNames;
    }



We can see implementation details in ImageIOUtil.writeImage
https://github.com/apache/pdfbox/blob/04292e421e9531616aa2856b908fbdb05b381af7/tools/src/main/java/org/apache/pdfbox/tools/imageio/ImageIOUtil.java#L65-L79

We can see it will create a File instance at first, then write image to TIF file.


As it create a File instance, this file will be created. It another application had read this file, then this file may be locked and failed to write.

Therefore, we should create TIF file to a temporary directory first, then move the finished TIF file to the destination. 




2016/10/06

[Mac] Yahoo 輸入法的全型與半型的切換

當我在 Mac 平台使用 Yahoo 輸入法時,當我切換為英數字的輸入時,若為全型時,該如何轉換成半型


此時你只要 shift + command + space ,即可將全型轉成半型



輸入結果如下


若要從半形再轉回全形,你只要再按一次 shift + command + space

2016/10/05

[Mac] Yahoo 輸入法如何中英切換

我在mac平台,使用yahoo輸入法作為我的中文輸入的工具


若我要從中文切換為英文的話,按下caps lock,即可輸入英文


但是此時會是小寫的英文,若要輸入大寫英文,只要按 shfit + 你要打的英文即可 (前提是你已經按下了 caps lock)


2016/10/04

[Java Mail] com.sun.mail.smtp.SMTPSendFailedException: 452 message processing failed: connection timeout

Problem
I am using JavaMail to send email. But I got this error message as bellows:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
DEBUG SMTP: MessagingException while sending, THROW: 
com.sun.mail.smtp.SMTPSendFailedException: 452 message processing failed: connection timeout

 at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2203)
 at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:1981)
 at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1197)
 at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:448)
 at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:345)
 at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)
 at com.yuantalife.ecp.commons.service.EmailService.send(EmailService.java:260)


How-to
This is not program's problem. This error may resulted from SMTP server. 
It may :

  1. The ISP server’s disk system has run out of storage space, so the action had to be cancelled.
  2. Most ISPs mail servers impose a maximum number of concurrent connections that client’s mail servers can attempt to make, and they usually also have a limit on the number of messages that are sent per connection.
  3. This error can also be indicative of a problem on your own mail server. ex. out of memory.

Reference
[1] http://www.answersthatwork.com/Download_Area/ATW_Library/Networking/Network__3-SMTP_Server_Status_Codes_and_SMTP_Error_Codes.pdf

2016/10/03

[Java] Lambda Expressions Example

If I have POJO, which named Person
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package albert.practice.lambda;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    private String name;
    private Gender gender;
    private int age;
    private String email;
    
}

If I have a List of Person, I would like to do search based on some criteria.

Example 1: I would like to find the person who is male and age is equal or greater than 25
Using Apache Commons Collection Utils:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private List<Person> findByApacheCommonsEx1(List<Person> dummyData) {
     return (List<Person>) CollectionUtils.select(dummyData, new Predicate() {
         @Override
         public boolean evaluate(Object object) {
              Person person = (Person) object;
              Boolean condition = person.getAge() >= 25 && Gender.MALE.equals(person.getGender());
              return condition;
         }
     });
}

Using Lambda Expression:
1
2
3
4
5
private List<Person> findByLambdaEx1(List<Person> dummyData) {
     return dummyData.stream()
                      .filter(person -> person.getAge() >= 25 && Gender.MALE.equals(person.getGender()))
                      .collect(Collectors.toList());
}


Example 2: I  would like to find the person who is equal or greater than 25, and find the first person from the collection.
Using Apache Commons Collection Utils:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private Person findByApacheCommonsEx2(List<Person> dummyData) {
     List<Person> result = (List<Person>) CollectionUtils.select(dummyData, new Predicate() {
         @Override
         public boolean evaluate(Object object) {
              Person person = (Person) object;
              return person.getAge() >= 25;
         }
     });

     Person person = null;
     if (!result.isEmpty()) {
         person = result.get(0);
     }
     return person;
}

Using Lambda Expression:
1
2
3
4
5
 private Person findByLambdaEx2(List<Person> dummyData) {
     Optional<Person> p = dummyData.stream()
                                         .filter(person -> person.getAge() >= 25).findFirst();
     return p.isPresent() ? p.get() : null;
 }


Example 3. Find List of String with criteria, throw RuntimeException if mismatch:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private List<String> getDummyPlayers() {
 return Arrays.asList("王 柏 融", "林 智 勝", "林 泓 育", "蔣 智 賢", "高 國 慶");
}

// using Apache Commons CollectionUtils
private void findPlayer() {
    List<String> players = getDummyPlayers();
    String name = "陳 金 鋒";
    List<String> result = (List<String>) CollectionUtils.select(players, new Predicate() {
            @Override
     public boolean evaluate(Object object) {
      String player = (String) object;
      return name.equals(player);
     }
    });

    if (CollectionUtils.isEmpty(result)) {
        throw new RuntimeException("Cannot find player with name " + name);
    }
}

// Using Lambda expression
private void findPlayer_usingJDK8() {
    List<String> players = getDummyPlayers();
    String name = "陳 金 鋒";
    players.stream().filter(player -> name.equals(player)).findFirst()
                    .orElseThrow(() -> new RuntimeException("Cannot find player with name " + name));
}    


Example 4. Remove duplicate item in List of String and do sort:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private List<String> getDummyPlayersWithDuplicateValue() {
    return Arrays.asList("王 柏 融", "林 智 勝", "林 泓 育", "王 柏 融", "林 智 勝", "蔣 智 賢", "高 國 慶");
}

// using Apache Commons CollectionUtils
private void removeDulpicatePlayerAndSort() {
    List<String> players = getDummyPlayersWithDuplicateValue();
    List<String> newList = new ArrayList<>();

    for (String player : players) {
        if (!newList.contains(player)) {
     newList.add(player);
 }
    }

    Collections.sort(newList, new Comparator<String>() {
 @Override
 public int compare(String o1, String o2) {
     return o1.compareTo(o2);
 }
    });

    newList.stream().forEach(player -> log.debug(player.toString()));
}

// Using Lambda expression
private void removeDulpicatePlayerAndSort_usingJDK8() {
    List<String> players = getDummyPlayersWithDuplicateValue();
    List<String> newList = players.stream().map(player -> player).distinct().sorted((o1, o2) -> o1.compareTo(o2))
      .collect(Collectors.toList());
    newList.stream().forEach(player -> log.debug(player.toString()));
}

Reference
[1] https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
[2] https://dzone.com/articles/why-java-8-1

2016/10/02

[閱讀筆記] 97 Things Every Programmer Should Know (2/2)


  1. API 設計的黃金準則是:只為你開發的API 編寫測試是不夠的;你必須為使用API 的程式編寫單元測試。你必須親身體驗,一旦你體驗過了,就可以面對每一種設計挑戰
  2. 專心在專案上,尋找聰明的解決方案來盡可能做出貢獻,提升你的技巧,反省你所做的,然後調整你的做法。別工作的像在籠子裡跑的倉鼠,每週工作超過60個小時是不明智的。要用專業的方式去做:準備、實現、觀察、反省與改變
  3. 一份好的bug report 需要包含三件事情
    1. 如何重現bug 以及出現的頻率
    2. 預期原本應該要發生什麼事情
    3. 實際上發生什麼事情
  4. IDE 工具的存在是為了讓開發更容易,並增進程式設計師的生產力。但是有時候妳應該掀開引擎蓋,了解你的IDE 為你做了什麼,最好的方法就是學習command-line tools。之後回過頭來使用IDE 就會更了解他正在為你做什麼,以及如何控制建置的過程。
  5. 評估、目標和承諾是彼此獨立的。但是,目標和承諾是建立在可靠的評估之上。軟體評估的主要目的並非預測專案的成果,而是為了判別專案的目標能否實現,讓專案得以掌控
  6. 評估時程的用意是為了使適當的專案管理與規劃成為可能,允許專案的利害關係人將於實現目標做出承諾
  7. 專案經理常對程式設計師要求的不是一個評估的時程,而是要對管理者內心不確定的目標做出承諾
  8. 一個好的interface 應是容易被正確的使用、難以被誤用。故你必須要事先預想到並避免使用者可能犯的錯誤,並觀察早期釋出的interface 如何被誤用並修改interface ,避免發生同樣錯誤
  9. 雖然在一般遇到的案例裡,使用 if - then - else 比多型更實用些,但絕大多數用 polymorphism 的寫作風格會讓程式碼更精簡、更易讀,且更少脆弱的程式碼。所以在我們的程式碼裡,要是錯過使用 polymorphism 的機會,便會逐漸增加  if - then - else 敘述句的數量。試試 command  pattern 吧
  10. deployment的環境資訊也要保持在版本控制之下。沒有比破壞一個環境設定,卻沒辦法知道哪裡被改變過還糟。環境資訊應該要與程式碼分開控制版本,因為他們改變的頻率與理由接不相同
  11. 如果你的程式碼需要註解來解釋,請考慮把它 refactor 到不再需要註解
  12. 專業程式設計師唯一最重要的特點就是個人的責任感。他們對自己擁有的職業負責,對確認自己的程式碼可以良好的運作負責,對自己工作產出的品質負責,即使當截止日期迫在眉睫,他們還是不放棄自己的原則。當壓力日益增加時,專家要比以往任何時候都更嚴格堅持著原則,他們知道這樣才是正確的
  13. 試圖挽救糟糕程式碼所浪費的時間,會比預想的多更多。一旦遇到怎麼修改都毫無起色的程式碼,應該立刻丟棄。修改糟糕程式碼的最好的方式就是換個做法,將程式碼無情的refactor 、移到別的地方或乾脆把它刪除掉。
  14. SRP(Single Responsibility Principle) 是良好設計的最基本原則,即將那些為了相同的理由而改變的東西聚集在一起,並將那些為了不同的理由而改變的東西獨立出來。
  15. 越接近交付期限,壓力越大,人本能的就開始偷工減料略過測試,所以你要想辦法把測試自動化,執行完就知道測試結果
  16. 你可以把 soak test 設定在假日執行 (如星期五半夜到下週一早上六點),藉此查看是否有 memory leak 的問題
  17. 當一個程式設計師,做個有經驗的技術專家已經不夠了,你還必須能與其他人有效率地一起工作
  18. 程式碼不會說謊,但是它卻會自我矛盾。有時候,錯加上錯就會變成對的,但它會變成更難以修復
  19. 良好的測試就像受測程式碼的文件一樣,它描述了程式碼如何運作。在每一個使用情境中,測試可以
    1. 描述出這些程式碼的執行脈絡、起始點或者必須滿足的前置條件
    2. 說明軟體如何被調用
    3. 描述出預期的結果或是需要驗證的 post condition
  20. 在測試的過程中,過多的程式碼會把閱讀你程式碼的人轉移到無關緊要的瑣事上,盡可能把這些瑣事使用具有意義命名的方法隱藏起來,這樣的方法稱為 extract method,這個 refactor 技巧會是你最好的朋友
  21. 你想要寫出良好的程式碼,並希望能成為一位好的程式設計師,你必須
    1. 在任何情況下,拒絕用 hack 的方式做出那種只是看似能夠運作的程式碼
    2. 你所寫的程式碼是淺顯易懂、易於維護、正確及確認已經解決問題
    3. 考慮到團隊的其他程式設計師,讓其他人可以讀懂你建構的程式碼
    4. check in 程式前,要讓程式碼比當初 check out 時來得更好 (如更好閱讀、更好的結構、更容易測試等)
    5. 持續學習新的語言、方法和技術,在適當的時機就可以派上用場
  22. 盡早挑戰你的客戶,並且要經常挑戰他們。別輕易的用他們的話重述他們告訴你的需求。請記住:客戶所告訴你的,不一定是他們想要的。客戶無法告訴你全部的事實,只是以客戶的方式陳述自己的想法,而非以開發人員的方式