Total Pageviews

2018/11/11

[Java] 如何連上政府資料開放平台,取得金融機構基本資料

Scenario

金融機構基本資料: https://data.gov.tw/dataset/6041


How-To
1. Add Maven dependency:
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>165test</groupId>
    <artifactId>test165</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test165</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-csv</artifactId>
            <version>1.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2. Bank Value Object: 用來儲存 CSV 解析後的結果
package test.vo;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

@Data
@Builder
@ToString
public class Bank {

    /*
     * 類別
     */
    private String type;

    /*
     * 總機構代號
     */
    private String headquarterCode;

    /*
     * 分支機構代號
     */
    private String branchCode;

    /*
     * 機構名稱
     */
    private String branchName;

    /*
     * 地址
     */
    private String address;

    /*
     * 緯度
     */
    private String latitude;

    /*
     * 經度
     */
    private String longitude;
    
    /*
     * 電話
     */
    private String phone;
    
    /*
     * 負責人
     */
    private String representative;
    
    /*
     * 異動日期
     */
    private String updateDate;
    
    /*
     * 金融機構網址
     */
    private String url;

}


3. Service class: 用來連上 open data URL,並解析獲得的結果,轉換成 List of Bank
package test.service;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import test.vo.Bank;
import test.vo.PostOffice;

public class OpenDataService {

    private static final String BANK_OPEN_DATA_URL = "https://quality.data.gov.tw/dq_download_csv.php?nid=6041&md5_url=4cbb7958872cb677421021ef63b2e2b9";

    public List<Bank> parseBankData() throws IOException {

        String csvData = "";
        try {
            csvData = getBankData();
        } catch (Exception e1) {
            throw new RuntimeException("金融機構基本資料 取得失敗, 錯誤原因: " + e1.getMessage(), e1);
        }

        List<Bank> bankData = new ArrayList<>();

        String[] FILE_HEADER = { "類別", "總機構代號", "分支機構代號", "機構名稱", "地址", "緯度", "經度", "電話", "負責人", "異動日期", "金融機構網址" };
        CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER);

        try (CSVParser csvFileParser = new CSVParser(new StringReader(csvData), csvFileFormat);) {
            List<CSVRecord> csvRecords = csvFileParser.getRecords();
            for (int i = 1; i < csvRecords.size(); i++) {
                CSVRecord record = csvRecords.get(i);
                String type = record.get("類別");
                String headquarterCode = record.get("總機構代號");
                String branchCode = record.get("分支機構代號");
                String branchName = record.get("機構名稱");
                String address = record.get("地址");
                String latitude = record.get("緯度");
                String longitude = record.get("經度");
                String phone = record.get("電話");
                String representative = record.get("負責人");
                String updateDate = record.get("異動日期");
                String url = record.get("金融機構網址");

                Bank bank = Bank.builder().type(type).headquarterCode(headquarterCode).branchCode(branchCode)
                        .branchName(branchName).address(address).latitude(latitude).longitude(longitude).phone(phone)
                        .representative(representative).updateDate(updateDate).url(url).build();
                bankData.add(bank);
            }
        } catch (IOException e) {
            throw new RuntimeException("金融機構基本資料 解析失敗, 錯誤原因: " + e.getMessage(), e);
        }
        return bankData;
    }

    public String getBankData() throws Exception {
        String bankDataStr = "";
        InputStream inputStream = null;
        try (CloseableHttpClient httpClient = createHttpsClient();) {
          
            HttpGet httpGet = new HttpGet(BANK_OPEN_DATA_URL);
            HttpResponse httpResponse = httpClient.execute(httpGet);

            inputStream = httpResponse.getEntity().getContent();
            bankDataStr = IOUtils.toString(inputStream, "UTF-8");
        } catch (NoSuchAlgorithmException | KeyManagementException | IOException e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
        return bankDataStr;
    }

    /**
     * 解決 PKIX path building failed 問題
     * 
     * @return HttpClient
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    private CloseableHttpClient createHttpsClient() throws NoSuchAlgorithmException, KeyManagementException {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        } };

        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, trustAllCerts, null);

        LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx);

        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build();
        return httpclient;
    }

}


4. Client class: 呼叫 Service class,並取得解析後的結果 (List of Bank)
package test;

import java.util.List;

import test.service.OpenDataService;
import test.vo.Bank;

public class OpenDataClient {

    public static void main(String[] args) throws Exception {
        OpenDataService service = new OpenDataService();
        List<Bank> banks = service.parseBankData();
        banks.forEach(b -> System.out.println(b.toString()));
    }

}

2018/11/10

[SchemaSpy] How to generate SQL Server schema document via SchemaSpy

Steps
1. Download SchemaSpy jar from http://schemaspy.org/
2. Downnload and install Graphviz from https://www.graphviz.org/
3. Download JDBC jar file for your target database
4. Execute command as bellows:
java -jar "F:\lib\schemaspy-6.0.0-rc2.jar" -dp "F:\sqljdbc_6.0\sqljdbc42.jar" -t mssql05 -db MyDB -host 192.168.0.1 -port 1433 -u user -p secret -charset UTF-8 -o "F:\Schema" -hq 



Commonly used parameters

  • -jar: The location of schemaspy jar file
  • -dp: NLooks for drivers here before looking in driverPath in [databaseType].properties. The drivers are usually contained in .jar or .zip files and are typically provided by your database vendor.
  • -t: Type of database (e.g. ora, db2, etc.)
  • -db: Name of database to connect to
  • -host: Databas URL to connect to
  • -port: Database port
  • -u: Valid database user id with read access.
  • -p: Valid password
  • -charset: Assign character set
  • -o: Directory to write the generated HTML/graphs to
  • -hq: Generate either higher-quality diagrams. 

2018/11/09

[SQL Server] Utilize FOR XML PATH to merge multiple rows into one row

Problem
Assume I get two rows from the following SQL statement:
select t1.CASEID, t1.PID, t1.NAME, t2.QVALUE + CHAR(10) + t2.AVALUE as QA
from TEXT_MAIN t1, TEXT_QA t2
where t1.CASEID = 'W00000003944' and t1.RID = t2.RID



If I would like to merge the two rows into one row:


How-To
You can use FOR XML PATH to fulfill this requirement, here has the example
select t1.CASEID, t1.PID, t1.NAME,
    (select t2.QVALUE + CHAR(10) + t2.AVALUE + CHAR(10)
     from TEXT_QA t2
     where t1.RID = t2.RID
     FOR XML PATH('')) as QA
from TEXT_MAIN t1
where t1.CASEID = 'W00000003944' 


2018/11/08

[Java] Using Java's Future and ExecutorService

Before

After

Example.
An enumeration class to store each product's price:
package test.albert.multithread;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum ProductEnum {
    P01("iPhone X  64G", 35900), 
    P02("iPhone X  256G", 41500), 
    P03("iPhone 8  64G", 25500), 
    P04("iPhone 8  256G", 30900), 
    P05("iPhone 8+ 64G", 28900), 
    P06("iPhone 8+ 256G", 34500);

    private String productName;
    private Integer amount;
}


An receipt class to store calculation result:

package test.albert.multithread;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Receipt {

    private String invoiceId;
    private ProductEnum product;
    private Integer unit;
    private Integer amount;
    private String recipient;

}


Callable is an interface that stands for a task that returns a result after some computations. This CalculationTask class contains our business logic, and every time a task starts, the call() method is executed.
package test.albert.multithread;

import java.util.UUID;
import java.util.concurrent.Callable;

public class CalculationTask implements Callable<Receipt> {

    private ProductEnum product;
    private Integer unit;
    private String recipient;

    public CalculationTask(ProductEnum product, Integer unit, String recipient) {
        this.product = product;
        this.unit = unit;
        this.recipient = recipient;
    }

    @Override
    public Receipt call() throws Exception {
        String invoiceId = UUID.randomUUID().toString();
        Integer amount = product.getAmount() * unit;
        
        return new Receipt(invoiceId, product, unit, amount, recipient);
    }

}


This is the CalculationTaskClient where we create an Executor service with a fixed number of threads. A separate task is created for every element in a list and is submitted it to the executor. Then, we get the result of computation with the help of the returned Future object in order to operate with it as we need it.
package test.albert.multithread;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CalculationTaskClient {

    private static final Integer THREADS_COUNT = 5;
    private static List<Order> orders = createDummyData();

    public static void main(String[] args) throws Exception {
        // Used to store calculation result.
        List<Receipt> receipts = new ArrayList<Receipt>();

        // Creates a thread pool that reuses a fixed number of threads operating off a
        // shared unbounded queue.
        ExecutorService executor = Executors.newFixedThreadPool(THREADS_COUNT);

        // Creates multiple callable tasks
        List<Callable<Receipt>> callables = new ArrayList<>();
        for (Order order : orders) {
            Callable<Receipt> task = new CalculationTask(order.getProduct(), order.getQuantity(), order.getBuyer());
            callables.add(task);
        }

        try {
            // Executes the given tasks, returning a list of Futures holding their status
            // and results when all complete.
            List<Future<Receipt>> results = executor.invokeAll(callables);
            
            // Get execution result.
            for (Future<Receipt> result : results) {
                receipts.add(result.get());
            }
        } catch (InterruptedException | ExecutionException e) {
            throw e;
        }

        executor.shutdown();

        receipts.forEach(r -> log.debug(r.toString()));
    }

    private static List<Order> createDummyData() {
        Order o1 = new Order(ProductEnum.P01, 2, "三澄美琴");
        Order o2 = new Order(ProductEnum.P02, 1, "中堂系");
        Order o3 = new Order(ProductEnum.P03, 1, "久部六郎");
        Order o4 = new Order(ProductEnum.P04, 4, "東海林夕子 ");
        Order o5 = new Order(ProductEnum.P05, 3, "三澄夏代");
        Order o6 = new Order(ProductEnum.P06, 10, "神倉保夫");
        Order o7 = new Order(ProductEnum.P01, 1, "糀谷夕希子");

        return Arrays.asList(o1, o2, o3, o4, o5, o6, o7);
    }

    @AllArgsConstructor
    @Data
    private static class Order {
        private ProductEnum product;
        private Integer quantity;
        private String buyer;
    }

}

2018/11/07

[Neo4j] Example for using unwind and shortestPath in Cypher

Scenario
以下是 Neo4j graph database 中的資料,假設我想:
(1) 找出某段時間,看診次數超過 3 次的 patients
(2) 找出 patients 間,關係長度為 2 的 patients


How-To
// 找出某段時間,看診次數超過 3 次的 patients
match (pat:Patient)-[r:VISIT]->(doc:Doctor)
where r.date >= "20180401" and r.date <= "20180430"
with pat, count(r.date) as count
where count >= 3

// 將 patient collection UNWIND 成一筆一筆資料
with collect(pat) as ps
unwind ps as p1
unwind ps as p2

// 找出 patients 間,關係長度為 2 的 patients
match  p = shortestPath((p1)-[*]-(p2))
where p1.name <> p2.name
with p1.name as patient1, p2.name as patient2, length(p) as length
where length = 2
return patient1, patient2, length


2018/11/06

[閱讀筆記] Value Investing: From Graham to Buffett and Beyond (2/7)


  1. Value of assets 的主要目的是透過公司資產的鑑價來看其資產價值與股票價格之間的落差,這之間的落差就是買賣的機會
  2. 存貨的入帳價值:主要有購貨價格、購貨費用、稅金等,其發出存貨的價值由以下方法確定:
先進先出法
(FIFO)
就是當發生銷貨,結轉銷貨成本時,採用的存貨成本順序。以先進先出為原則,亦即愈早買入存貨的愈先結轉。
後進先出法
(FILO)
以較晚買入的(最近期買入)的存貨成本先結轉。
加權平均法
一般是用在永續盤存制,每次進價及數量可能都不相同, 因此在每次進貨後都要重新計算帳上存貨的單位平均成本。
移動加權平均法
每一期期末 (例如月底或年底) 才計算進貨的成本及數量多少, 再來計算當期每單位存貨平均成本,以該單位成本計算銷貨成本等數字。 一般是定期盤存制下使用。
個別計價法
是以每次()收入存貨的實際成本作為計算各該次()發出存貨成本的依據。即:每次()存貨發出成本=該次()存貨發出數量X該次()存貨實際收入的單位成本除上述計價法外,還有計劃成本法、毛利率法、售價金額核演算法等,但前五種方法屬於企業按實際成本計價的存貨發出的計價方法。存貨期末計價通常是以實際成本確定。但是.除了這種方法外.還有一較為廣泛的方法——成本(實際成本)與可變現凈值兩者之中較低者計價的方法。

  1. 在通貨膨脹環境中,採用先進先出法,主營成本中的原材料成本是較早時間採購的價格較低的原材料,如果公司產品價格也因通脹因素上漲,就會推高公司利潤。相反,如果採用後進先出法,損益表中的成本和毛利就更為真實,公司利潤不會因通脹因素出現虛增。目前大多數公司都採取先進先出法,而且一般不會頻繁改變存貨會計政策。如果一旦改變,通常會令當期業績出現較大變動,這也是公司管理層操縱業績的手段之一,對此投資者需要有所辨別。在缺乏遊戲規則的情形下,企業將有機會利用高低存貨成本的結轉,輕易地操縱企業的獲利數字,導致財務報表無法真實表達企業的經營狀況,所以會計上針對存貨成本的運用有一定的規範。
  2. Goodwill (商譽)一詞也算是會計中最彆扭的了。在大部份上市公司的資產負責表你會見到這個項目。你懂會計的話,你會知道這一個字便暴露了會計這個系統的其中一個重大漏洞。收購另一間公司都有溢價,因為如果被收購公司只值其資產總和,那收購方不如在市場分開買那些資產,不用麻煩。所以公司一經歷收購,便會有一定的Goodwill 千秋萬世永留在資產負債表上。有很多國際級企業的Goodwill 可達總資產的20%不等,那是因為它真的很有「商譽」﹗如迪士尼、微軟級數的公司,它真的有很多無形資產是用Goodwill 去涵蓋的,它的賺錢能力遠比它的有形資產所代表的多。如果你買起迪士尼的所有有形資產,不代表你可以有迪士尼的賺錢能力。因為你買不到它的企業文化、它的員工、它的創意和最重要迪士尼這個品牌。 真正要小心的,是名不經傳的小上市公司,有著佔資產50%Goodwill。記著Goodwill是空氣,這些公司碰也不能碰
  3. EBITDA (Earnings before Interest, Taxes, Depreciation, and Amortization) 是從1980年代的槓桿收購 (LBO) 熱潮期間開始廣為人知,當時它主要用來評估企業的償債能力。雖然名稱看起來很複雜,用簡單一點的話來說就是不包含"稅、利息、折舊&攤銷費用"的盈餘。後來,這項指標在某些資本密集型產業很流行,這些業者擁有昂貴的固定資產,必須分多年攤提折舊費用。目前,許多企業都會公布EBITDA,科技業尤其喜歡強調這項指標,雖然EBITDA對分析這些公司的表現,未必有多大的意義。許多人誤以為 EBITDA 代表公司的現金盈利,但其實這項指標雖然能反映公司的盈利能力,但並不是評估公司現金流的好指標。EBITDA 並末考慮公司維持營運資金與汰換老舊設備的現金需求,這兩者都可能不容小覷。EBITDA 往往成了企業美化盈利表現的會計花招,投資人不應該只看這項數據,應綜合分析公司的績效指標,發掘可能遭 EBITDA 掩蓋的真相
  4. 當你所提供的商品或服務,進入門檻低,大家都可以模仿與生產,消費者也難以辨識不同廠牌的商品或服務時,就會陷入價格競爭,企業的利潤就會下滑,earning power 就會降低,因為消費者只會選擇便宜的商品或服務。為了避免陷入此種命運,你只能與其他競爭對手差異化 (differentiate) 你的商品或服務
  5. 若你的產品或服務陷入紅海競爭,你會發現,銷售量減少了,但是固定成本 (fixed costs) 並未下降 (如產品發展、包裝設計與廣告費用等),有時候甚至為了強打廣告反而增加更多的成本,導致淨利率(profit margin) 下滑
  6. 光看盈利數字,難以看出公司的盈利能力,因為盈利增長,不代表公司的淨利率 (profit margin) 也一定上升。例如,當公司的成本上升速度快過營收時,淨利率會下滑,意味著公司或許應加強控制成本。舉例來說,某公司上年度營收1億元,淨利1000萬元,淨利率即為10%(1000/1億元)。若本年度營收及淨利分別增至2億元與1500萬元,則其淨利率已跌至7.5%。公司盈利雖大幅成長,但代價是淨利率下滑。
  7. 維持 earning power 的主要來源
        9.1.     特許經營權 (franchises)
        9.2.     進入障礙 (barriers to entry)
        9.3.     現有的競爭優勢 (incumbent competitive advantages)
  1. 取得特許經營權 (franchises) 優勢,最簡單的方式是取得政府的授權 (license),也就是經營執照,例如有線電視、廣播、電視、電力設施等,沒有取得經營執照的廠商是無法進入此市場
  2. 若能夠在生產產品的流程擁有優於當前市場的成本優勢 (cost advantages) ,且讓潛在進入者無法跟上,就能杜絕潛在的競爭者進入你現在擁有的市場
  3. 轉換成本 (switching costs) 也是常見的、有力的綁住客戶的競爭優勢,如軟體產業的 Microsoft,當大部分的使用者都已經熟悉 Microsoft 的軟體使用,很少使用者願意投入額外的學習成本來嘗試替代品。同樣的道理也發生在律師、銀行、提供醫療服務的醫療院所等,這些人已經熟悉現有的系統、醫療保險計畫與藥物等,若要醫生開新的治療藥物,他就必須學習新的療法的成效與潛在的風險
  4. 為了要綁住客戶,企業常用的手段有:
提高轉換成本
(raising switching costs)
在現有的產品與服務不斷增加新的功能、特色與服務,Microsoft 就是採用此種策略
強化使用者習慣
(reinforcing habits)
提昇消費者購買頻率,建立起定期消費的習慣
提高搜尋成本
(raising searching costs)
增加與複雜化所提供的服務範圍,強化現有客戶滿意度

  1. 對於市場新的進入者來說,則是要做與上述相反的手段,將搜尋與轉換成本最小化。例如信用卡公司提供轉換者 (switcher) 預先核定的信用額度 (credit balances),並提供獎勵給轉換者;又如電信公司提供快速 NP 的服務,並給予購機折扣
  2. 對於那些基於規模經濟 (economies of scale) 所建立起競爭優勢的公司,其首要之務是保護市佔率 (market share),因為規模經濟的優勢就是擁有較低的平均成本,賺得較佳的營收。一旦市佔率開始被侵蝕,基於規模經濟所建立起的成本優勢 (cost advantages) 就會開始萎縮。
  3. 特許經營權 (franchises) 只存在於擁有進入障礙 (barriers to entry) 的企業,將潛在的競爭者隔絕在外,或者是一旦有新的進入者,確保他們的產品或服務處於競爭劣勢 (competitive disadvantage)
  4. 好的管理的確是一個優勢,但是若沒有建立起實質的競爭優勢,企業是無法永續經營的
  5. 實質的競爭優勢包含:
      18.1.     獨家的政府授權
      18.2.     消費者偏好 (需求面)
      18.3.     基於長久的專利保護或其他持久的優異性所取得的成本優勢 (供給面)
      18.4.     由於領先的市佔率與消費者偏好所組成的規模經濟
  1. 品牌價值 (brand value) 或許是察覺產品價值的一個重要元素,但是品牌價值無法建立進入障礙 (barriers to entry) 或競爭優勢。只有提高轉換成本 (raising switching costs)、強化使用者習慣 (reinforcing habits) 與提高搜尋成本 (raising searching costs) 才能綁住顧客
  2. 品牌價值要靠規模經濟來強化。僅在每台個人電腦貼上 Intel Inside 貼紙是無法建立起強大的品牌,還需要伴隨著在晶片設計與生產擁有強大的規模經濟
  3. 資本成本 (Cost of Capital),是企業進行財務決策時的重要的指標。開設公司若錢不夠,就需要對外借錢,如銀行、股東等等。當企業借錢的時候,需要付出一定的代價,主要有兩方面:其一是「籌資費用」,也就是銀行手續費、股票債券發行費、律師費、廣告費、審計費等等。另一方面就是「占用成本」,也就是付給股東的股利、股息,還有給債權人的利息等等。 
  4. 對於企業來說,希望資本成本  (cost of capital) 越低越好,用最小的代價,借到最多的錢。在企業決定借錢的時候,往往會面臨許多選擇,在單次籌集資金數量等同的前提下,多半會選擇資本成本較低的籌資方式。資本成本越低,就越接近企業價值最大化的經營目標。
  5. 資本成本 (cost of capital) 的高低取決於市場對這個公司的風險預期。風險越高,投資者要求的回報率越高,公司的資本成本也就越高。因此,資本成本也可以定義為投資者所要求的最低收益率。也可以說,資本成本對投資者而言,是一種使用經濟資源的機會成本。如果投資回報率低於資本成本,也就是風險預期,就不該進行投資
  6. 就稅前的角度來看,負債的資金成本其實就是利息,所以如果以百分比表達的話,應該就是利率。 但是, 股東關心的是公司的稅後現金流量,所以資金成本應該採用稅後的資金成本的觀念。資金成本就要依公司稅率調整。
  7. 利息是一種費用,可以抵稅,所以等於是政府幫忙負擔公司利息費用的一部份。所以,公司的實際負擔利率較低,因此,負債資金成本就是 : 利率×(1-稅率) 。至於股息,不管是普通股或特別股股息都是稅後盈餘的分配,無法抵稅,所以權益資金成本無法像利息一般乘上(1-稅率)