Java單元測試之模擬利器-使用PowerMock進行Mock測試

Powermock介紹

簡介

mock是模擬對象,用於模擬真實對象的行爲。html

Powermock主要用於打樁。好比:方法A的參數須要傳入實例B,方法A須要調用B的某個方法B.C()。方法C由於耗時長或者根本沒有實現或者其餘不方便在單元測試中實現等緣由,須要僞造返回,此時Powermock便可派上用場。java

PowerMock擴展了EasyMock和Mockito框架,增長了對static和final方法mock支持等功能。這裏主要基於PowerMock Mockito API進行介紹。python

PowerMock支持JUnit和TestNG,這裏基於JUnit。git

 

 

介紹

本文地址:http://my.oschina.net/u/1433482/blog/645155  。程序員

交流:python開發自動化測試羣291184506 PythonJava單元白盒單元測試羣144081101github

英文原版書籍下載:https://bitbucket.org/xurongzhong/python-chinese-library/downloadssweb

精品文章推薦:正則表達式

python 2.7 中文教程及自動化測試介紹算法

使用Python學習selenium測試工具spring

性能測試藝術
Java單元測試之模擬利器-使用PowerMock進行Mock測試


 

安裝

    下載地址:https://github.com/jayway/powermock/wiki/Downloads。下載" Mockito and JUnit including dependencies"版本。當前版本爲」powermock-mockito-junit-1.6.3.zip"。 

    IntelliJ IDEA的設置以下:

    右擊工程,選擇「Open Module Settings」

    

    

    按下「ALT + Insert」,選擇「Jars or directories...", 插入jar包:

    

    點擊OK。

    在」Module Settings」對話框中點擊「Sources」標籤,右擊右邊底部面板,選擇「New Folder...", 命名爲test。

    在」Module Settings」對話框中選擇test,標識爲Test Sources,關閉」Module Settings」對話框。

    Eclipse中只須要上述jar包放在工程下的lib目錄便可。

    Maven在pom.xml添加以下內容:

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>1.6.3</version>
        <scope>test</scope>
    </dependency>    
    <dependency>    
        <groupId>org.powermock</groupId>    
        <artifactId>powermock-api-mockito</artifactId>    
        <version>1.6.3</version>    
        <scope>test</scope>    
    </dependency>        
  </dependencies>

快速入門

    下面建立EmployeeController類用於給Employee類執行Create, Read, Update, and Delete (CRUD)。實際工做由EmployeeService完成。getProjectedEmployeeCount方法預計公司員工每一年增長20%,並返回近似取整。

     

public class EmployeeController {
    
    private EmployeeService employeeService;
    
    public EmployeeController(EmployeeService employeeService) {
    
        this.employeeService = employeeService;
    }
    
    public int getProjectedEmployeeCount() {
    
        final int actualEmployeeCount = employeeService.getEmployeeCount();
        return (int) Math.ceil(actualEmployeeCount * 1.2);
    }
    
    public void saveEmployee(Employee employee) {
    
        employeeService.saveEmployee(employee);
    }    
}
public class EmployeeService {
    
    public int getEmployeeCount() {
        throw new UnsupportedOperationException();
    }
    
    public void saveEmployee(Employee employee) {
        throw new UnsupportedOperationException();
    }    
}

     

    因爲getEmployeeCount等方法沒有真正實現,咱們須要mock:

public class Employee {

}
import static org.junit.Assert.*;

import org.junit.Test;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;

public class EmployeeControllerTest {

    @Test
    public void shouldReturnProjectedCountOfEmployeesFromTheService() {
        
        EmployeeService mock = PowerMockito.mock(EmployeeService.class);
        PowerMockito.when(mock.getEmployeeCount()).thenReturn(8);
        EmployeeController employeeController = new EmployeeController(mock);
        assertEquals(10, employeeController.getProjectedEmployeeCount());
    }
    
    @Test
    public void
    shouldInvokeSaveEmployeeOnTheServiceWhileSavingTheEmployee() {
        
        EmployeeService mock = PowerMockito.mock(EmployeeService.class);    
        EmployeeController employeeController = new EmployeeController(mock);
        Employee employee = new Employee();
        employeeController.saveEmployee(employee);
        Mockito.verify(mock).saveEmployee(employee);
    }        
}

    

     注意若是上述代碼出現莫名其妙的錯誤,建議先確認全部文件已經保存,再不行重啓Eclipse。

    上面的saveEmployee(Employee)沒有返回值,咱們只須要用verify確認有調用便可。若是註釋掉employeeController.saveEmployee(employee);就會有以下報錯:

    Wanted but not invoked:
employeeService.saveEmployee(
    Employee@51081592
);
-> at EmployeeControllerTest.shouldInvokeSaveEmployeeOnTheServiceWhileSavingTheEmployee(EmployeeControllerTest.java:27)
Actually, there were zero interactions with this mock.
    at EmployeeControllerTest.shouldInvokeSaveEmployeeOnTheServiceWhileSavingTheEmployee(EmployeeControllerTest.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

    另外有個很是用的MockSettings功能,用於設置mock名、實現額外接口(參見https://groups.google.com/forum/?fromgroups=#!topic/mockito/YM5EF0x90_4)、開啓詳細日誌、註冊listener用於mock時通知消息調用。好比:

    EmployeeService mock = PowerMockito.mock(EmployeeService.class, Mockito.withSettings().name("EmployeeServiceMock").verboseLogging());

從上面例子能夠看出,mock經常使用於參數,若是是方法內部的局部變量偏多、邏輯過於複雜,mock將是比較痛苦的過程,甚至無從下手。    

注意:Eclipse若是看不到lib,請選中工程目錄,按F5刷新。lib中的每一個jar,須要右鍵點擊,選擇"Build Path"->"Add to Build Path", 添加完畢的效果圖以下:

   

模擬靜態方法

    修改類Employee:

public class Employee {
    
    public static int count() {
        throw new UnsupportedOperationException();
    }
}

    修改EmployeeService類的方法:

    public int getEmployeeCount() {    
        return Employee.count();
    }

    新建EmployeeServiceTest類:

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Employee.class)
public class EmployeeServiceTest {

    @Test
    public void shouldReturnTheCountOfEmployeesUsingTheDomainClass() {
        
        PowerMockito.mockStatic(Employee.class);
        PowerMockito.when(Employee.count()).thenReturn(900);
        
        EmployeeService employeeService = new EmployeeService();
        assertEquals(900, employeeService.getEmployeeCount());
        
    }
}

@RunWith(PowerMockRunner.class)語句告訴JUnit用PowerMockRunner來執行測試。
@PrepareForTest(Employee.class)語句告訴PowerMock準備Employee類進行測試。適用於模擬final類或有final, private, static, native方法的類。

    
注意這裏使用的是mockStatic而不是上面的mock。

    下面咱們模擬下返回void的靜態方法。在Employee添加加薪方法:

    public static void giveIncrementOf(int percentage) {
        throw new UnsupportedOperationException();
    }

    

    EmployeeService添加相應方法:

    public boolean giveIncrementToAllEmployeesOf(int percentage) {
        try{
            Employee.giveIncrementOf(percentage);
            return true;
        } catch(Exception e) {
            return false;
        }
    }

    

    修改EmployeeServiceTest類

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
 
@RunWith(PowerMockRunner.class)
@PrepareForTest(Employee.class)
public class EmployeeServiceTest {
 
    @Test
    public void shouldReturnTrueWhenIncrementOf10PercentageIsGivenSuccessfully() {
        
        PowerMockito.mockStatic(Employee.class);
        PowerMockito.doNothing().when(Employee.class);
        Employee.giveIncrementOf(10);
        EmployeeService employeeService = new EmployeeService();
        assertTrue(employeeService.giveIncrementToAllEmployeesOf(10));
        
    }
    
    @Test
    public void shouldReturnFalseWhenIncrementOf10PercentageIsNotGivenSuccessfully() {
        
        PowerMockito.mockStatic(Employee.class);
        PowerMockito.doThrow(new IllegalStateException()).when(Employee.class);
        Employee.giveIncrementOf(10);
        EmployeeService employeeService = new EmployeeService();
        assertFalse(employeeService.giveIncrementToAllEmployeesOf(10));
    }    
}

    

    PowerMockito.doNothing方法告訴PowerMock下一個方法調用時什麼也不作。

    PowerMockito.doThrow方法告訴PowerMock下一個方法調用時產生異常。

    PowerMock使用自定義類加載器和字節碼操做來模擬靜態方法。對於實例中沒有mock的方法,也有默認返回值,好比返回int類型的方法,默認返回0。

    
PowerMockito.doNothing和PowerMockito.doThrow的語法可用於實例方法。

    先在Employee類添加方法save:

    public void save() {
        throw new UnsupportedOperationException();
    }

    

    建立測試EmployeeTest 類:

import static org.junit.Assert.*;

import org.junit.Test;
import org.powermock.api.mockito.PowerMockito;

public class EmployeeTest {
    
    @Test()
    public void shouldNotDoAnythingIfEmployeeWasSaved() {
    
        Employee employee = PowerMockito.mock(Employee.class);
        PowerMockito.doNothing().when(employee).save();
        try {
            employee.save();
        } catch(Exception e) {
            fail("Should not have thrown an exception");
        }
    }
    
    @Test(expected = IllegalStateException.class)
    public void shouldThrowAnExceptionIfEmployeeWasNotSaved() {
    
        Employee employee = PowerMockito.mock(Employee.class);
        PowerMockito.doThrow(new IllegalStateException()).when(employee).save();
        employee.save();
    }
}

    注意這裏doThrow和doNothing方法不會對下一行產生影響。

驗證方法調用

    驗證斷言方法是否調用。

    修改EmployeeService類的saveEmployee方法。

    public void saveEmployee(Employee employee) {
        if(employee.isNew()) {
            employee.create();
            return;
        }
        employee.update();
    }

修改Employee類,新增以下方法:

    public boolean isNew() {
        throw new UnsupportedOperationException();
    }
    
    public void update() {
        throw new UnsupportedOperationException();
    }
    
    public void create() {
        throw new UnsupportedOperationException();
    }
    
    public static void giveIncrementOf(int percentage) {
        throw new UnsupportedOperationException();
    }

在EmployeeServiceTest類中新增shouldCreateNewEmployeeIfEmployeeIsNew方法, 並新增導入import org.mockito.Mockito;:

    @Test
    public void shouldCreateNewEmployeeIfEmployeeIsNew() {
    
        Employee mock = PowerMockito.mock(Employee.class);
        PowerMockito.when(mock.isNew()).thenReturn(true);
        EmployeeService employeeService = new EmployeeService();
        employeeService.saveEmployee(mock);
        Mockito.verify(mock).create();
        Mockito.verify(mock, Mockito.never()).update();
    }

 Mockito.verify(mock).create()驗證調用了create方法。 Mockito.verify(mock, Mockito.never()).update();驗證沒有調用update方法。

 

下面驗證靜態方法,在EmployeeServiceTest類添加shouldInvoke_giveIncrementOfMethodOnEmployeeWhileGivingIncrement方法:

   

    @Test
    public void shouldInvoke_giveIncrementOfMethodOnEmployeeWhileGivingIncrement() {
    
        PowerMockito.mockStatic(Employee.class);
        PowerMockito.doNothing().when(Employee.class);
        Employee.giveIncrementOf(9);
        EmployeeService employeeService = new EmployeeService();
        employeeService.giveIncrementToAllEmployeesOf(9);
        PowerMockito.verifyStatic();
        Employee.giveIncrementOf(9);
    }

一樣,靜態驗證也要分兩步走。

其餘驗證模式能夠驗證調用次數:

  • Mockito.times(int n) : This verification mode asserts that the mocked method was invoked exactly 'n' times

  • Mockito.atLeastOnce() : This verification mode asserts that the mocked method was invoked at least once

  • Mockito.atLeast(int n) : This verification mode asserts that the mocked method was invoked at least 'n' times

  • Mockito.atMost(int n) : This verification mode asserts that the mocked method was invoked at most 'n' times

使用Mockito.inOrder還能夠驗證調用的順序,注意要導入import org.mockito.InOrder;

   

    @Test
    public void shouldInvokeIsNewBeforeInvokingCreate() {
        
        Employee mock = PowerMockito.mock(Employee.class);
        PowerMockito.when(mock.isNew()).thenReturn(true);
        EmployeeService employeeService = new EmployeeService();
        employeeService.saveEmployee(mock);
        InOrder inOrder = Mockito.inOrder(mock);
        inOrder.verify(mock).isNew();
        Mockito.verify(mock).create();
        Mockito.verify(mock, Mockito.never()).update();
    }

 

模擬final類或方法

新增EmployeeIdGenerator類:

public final class EmployeeIdGenerator {

    public final static int getNextId() {
        throw new UnsupportedOperationException();
    }
}

 

在Employee類新增方法:

    public void setEmployeeId(int nextId) {

        throw new UnsupportedOperationException();        
    }

 

修改EmployeeService類的saveEmployee方法:

    public void saveEmployee(Employee employee) {
        if(employee.isNew()) {
            employee.setEmployeeId(EmployeeIdGenerator.getNextId());
            employee.create();
            return;
        }
        employee.update();
    }

修改EmployeeServiceTest類:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
 
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeIdGenerator.class)
public class EmployeeServiceTest {
    
    @Test
    public void shouldGenerateEmployeeIdIfEmployeeIsNew() {
        
        Employee mock = PowerMockito.mock(Employee.class);
        PowerMockito.when(mock.isNew()).thenReturn(true);
        PowerMockito.mockStatic(EmployeeIdGenerator.class);
        PowerMockito.when(EmployeeIdGenerator.getNextId()).thenReturn(90);
        EmployeeService employeeService = new
        EmployeeService();
        employeeService.saveEmployee(mock);
        PowerMockito.verifyStatic();
        EmployeeIdGenerator.getNextId();
        Mockito.verify(mock).setEmployeeId(90);
        Mockito.verify(mock).create();
    }
}

可見final和static的在類頭部處理方法相似,二者能夠基本歸爲一類。

其餘java mock框架大多基於代理模式,參見https://en.wikipedia.org/wiki/Proxy_pattern#Example 。這種方式嚴重依賴子類及方法能夠重載。因此不能模擬final和static。

 

 處理構造方法

如今建立新職員的時候要發送歡迎郵件。

新增類WelcomeEmail:

public class WelcomeEmail {

    public WelcomeEmail(final Employee employee, final String message) {
        throw new UnsupportedOperationException();
    }
    
    public void send() {
        throw new UnsupportedOperationException();
    }
}

 

修改EmployeeService類的saveEmployee方法:

    public void saveEmployee(Employee employee) {
        if(employee.isNew()) {
            employee.setEmployeeId(EmployeeIdGenerator.getNextId());
            employee.create();
            WelcomeEmail emailSender = new WelcomeEmail(employee,
            "Welcome to Mocking with PowerMock How-to!");
            emailSender.send();
            return;
        }
        employee.update();
    }
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
 
@RunWith(PowerMockRunner.class)
@PrepareForTest({EmployeeIdGenerator.class, EmployeeService.class})
public class EmployeeServiceTest {

    @Test
    public void shouldSendWelcomeEmailToNewEmployees()throws Exception {
        
        Employee employeeMock =PowerMockito.mock(Employee.class);
        PowerMockito.when(employeeMock.isNew()).thenReturn(true);
        PowerMockito.mockStatic(EmployeeIdGenerator.class);
        WelcomeEmail welcomeEmailMock = PowerMockito.mock(WelcomeEmail.class);
        PowerMockito.whenNew(WelcomeEmail.class).withArguments(employeeMock, "Welcome to Mocking with PowerMock How-to!").thenReturn(welcomeEmailMock);
        EmployeeService employeeService = new EmployeeService();
        employeeService.saveEmployee(employeeMock);

        PowerMockito.verifyNew(WelcomeEmail.class).withArguments(employeeMock, "Welcome to Mocking with PowerMock How-to!");
        Mockito.verify(welcomeEmailMock).send();
    }
}

注意PowerMockito.verifyNew的第2個參數支持前面提到的驗證模式。PowerMockito.whenNew().withArguments(...).thenReturn()是對構造方法的mock模式,PowerMockito.verifyNew().withArguments()是驗證模式。

參數匹配

 PowerMock使用equals方法驗證參數。matcher可更加靈活的處理參數。

爲EmployeeController類添加以下方法:

   

    public Employee findEmployeeByEmail(String email) {    
        return employeeService.findEmployeeByEmail(email);
    }
        
    public boolean isEmployeeEmailAlreadyTaken(String email) {
        Employee employee = new Employee();
        return employeeService.employeeExists(employee);
    }

爲EmployeeService類添加以下方法:

   

    public Employee findEmployeeByEmail(String email) {
        throw new UnsupportedOperationException();
    }
    
    public boolean employeeExists(Employee employee) {
        throw new UnsupportedOperationException();
    }

  

爲EmployeeControllerTest類新增測試

    @Test
    public void shouldFindEmployeeByEmail() {
    
        final EmployeeService mock = PowerMockito.mock(EmployeeService.class);
        final Employee employee = new Employee();
        PowerMockito.when(mock.findEmployeeByEmail(Mockito.startsWith("deep"))).thenReturn(employee);
        final EmployeeController employeeController = new EmployeeController(mock);
        assertSame(employee, employeeController.findEmployeeByEmail("deep@gitshah.com"));
        assertSame(employee, employeeController.findEmployeeByEmail("deep@packtpub.com"));
        assertNull(employeeController.findEmployeeByEmail("noreply@packtpub.com"));
    }
    
    @Test
    public void shouldReturnNullIfNoEmployeeFoundByEmail() {
        
        final EmployeeService mock = PowerMockito.mock(EmployeeService.class);
        PowerMockito.when(mock.findEmployeeByEmail(Mockito.anyString())).thenReturn(null);
        final EmployeeController employeeController = new EmployeeController(mock);
        assertNull(employeeController.findEmployeeByEmail("deep@gitshah.com"));
        assertNull(employeeController.findEmployeeByEmail("deep@packtpub.com"));
        assertNull(employeeController.findEmployeeByEmail("noreply@packtpub.com"));        
    }

 後面還有個基於argThat例子,由於沒有搞到源碼,意思暫時沒有揣度出來。先不涉及。

另外其餘相似的內置匹配器以下:Mockito.eq、Mockito.matches、Mockito.any(anyBoolean , anyByte , anyShort , anyChar , anyInt ,anyLong , anyFloat , anyDouble , anyList , anyCollection , anyMap , anySet等等)、Mockito.isNull、Mockito.isNotNull、Mockito.endsWith、Mockito.isA。

 

回答(Answer)

在某些邊緣的狀況下不可能經過簡單地經過PowerMockito.when().thenReturn()模擬,這時可使用Answer接口。

在EmployeeControllerTest類中增長以下方法:

import org.mockito.stubbing.Answer;
  
public class EmployeeControllerTest {
  
    @Test
    public void shouldFindEmployeeByEmailUsingTheAnswerInterface() {
         
        final EmployeeService mock = PowerMockito.mock(EmployeeService.class);
        final Employee employee = new Employee();
        
        PowerMockito.when(mock.findEmployeeByEmail(Mockito.anyString())).then(new Answer<Employee>() {

            public Employee answer(InvocationOnMock invocation) throws Throwable {
                final String email = (String) invocation.getArguments()[0];
                if(email == null) return null;
                if(email.startsWith("deep")) return employee;
                if(email.endsWith("packtpub.com")) return employee;
                return null;
            }
        });
        
        final EmployeeController employeeController = new EmployeeController(mock);
        assertSame(employee, employeeController.findEmployeeByEmail("deep@gitshah.com"));
        assertSame(employee, employeeController.findEmployeeByEmail("deep@packtpub.com"));
        assertNull(employeeController.findEmployeeByEmail("hello@world.com"));
    }
         
    @Test
    public void shouldReturnCountOfEmployeesFromTheServiceWithDefaultAnswer() {
         
        EmployeeService mock = PowerMockito.mock(EmployeeService.class, new Answer() {
            
            public Object answer(InvocationOnMock invocation) {
                return 10;
            }
        });
        
        EmployeeController employeeController = new EmployeeController(mock);
        assertEquals(12, employeeController.getProjectedEmployeeCount());
    }
}

 

Answer接口指定執行的action和返回值執。 Answer的參數是InvocationOnMock的實例,支持:

  • callRealMethod():調用真正的方法

  • getArguments():獲取全部參數

  • getMethod():返回mock實例調用的方法

  • getMock():獲取mock實例

第一個測試方法根據不一樣狀況構造不一樣返回。第2個測試方法設定調用返回的默認值。

使用spy進行部分模擬

如今調整類EmployeeService,拆分saveEmployee爲方法:saveEmployee和createEmployee:

    public void saveEmployee(Employee employee) {
        if(employee.isNew()) {
            createEmployee(employee);
            return;
        }
        employee.update();
    }  
    
    void createEmployee(Employee employee) {
        employee.setEmployeeId(EmployeeIdGenerator.getNextId());
        employee.create();
        WelcomeEmail emailSender = new WelcomeEmail(employee,
        "Welcome to Mocking with PowerMock How-to!");
        emailSender.send();
    }

EmployeeServiceTest類添加測試方法shouldInvokeTheCreateEmployeeMethodWhileSavingANewEmployee:

    @Test
    public void shouldInvokeTheCreateEmployeeMethodWhileSavingANewEmployee() {
        
        final EmployeeService spy = PowerMockito.spy(new EmployeeService());
        final Employee employeeMock = PowerMockito.mock(Employee.class);
        PowerMockito.when(employeeMock.isNew()).thenReturn(true);
        PowerMockito.doNothing().when(spy).createEmployee(employeeMock);
        spy.saveEmployee(employeeMock);
        Mockito.verify(spy).createEmployee(employeeMock);      
    }

注意spy只能使用PowerMockito.doNothing()/doReturn()/doThrow()。

模擬私有方法

如今咱們修改EmployeeService.createEmployee爲private,在EmployeeServiceTest類添加以下方法:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
 
@RunWith(PowerMockRunner.class)
@PrepareForTest({EmployeeIdGenerator.class, EmployeeService.class})
public class EmployeeServiceTest {
    
    @Test
    public void shouldInvokeTheCreateEmployeeMethodWhileSavingANewEmployee() throws Exception {
         
        final EmployeeService spy = PowerMockito.spy(new EmployeeService());
        final Employee employeeMock = PowerMockito.mock(Employee.class);
        PowerMockito.when(employeeMock.isNew()).thenReturn(true);
        PowerMockito.doNothing().when(spy, "createEmployee", employeeMock);
        spy.saveEmployee(employeeMock);
        PowerMockito.verifyPrivate(spy).invoke("createEmployee", employeeMock);
    }
}

模擬私有方法還有另一種相對較複雜的方法,這裏不作介紹了。

 

查看封裝內容

添加 Department類

import java.util.ArrayList;
import java.util.List;

public class Department {
    
    private List<Employee> employees = new ArrayList<Employee>();    
    private long maxSalaryOffered;
    public void addEmployee(final Employee employee) {
        employees.add(employee);
        updateMaxSalaryOffered();
    }
    
    /**
    * The private method that keeps track of
    * max salary offered by this department.
    */
    private void updateMaxSalaryOffered() {
        maxSalaryOffered = 0;
        for (Employee employee : employees) {
            if(employee.getSalary() > maxSalaryOffered) {
                maxSalaryOffered = employee.getSalary();
            }
        }
    }
}

修改Employee類的以下方法:

    public long getSalary() {
        return salary;      
    }
    
    public void setSalary(int i) {
        salary = i;        
    }

新建DepartmentTest類,添加以下測試方法:

import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.powermock.reflect.Whitebox;

public class DepartmentTest {
    @Test
    public void shouldVerifyThatNewEmployeeIsAddedToTheDepartment() {
        
        final Department department = new Department();
        final Employee employee = new Employee();
        department.addEmployee(employee);
        final List<Employee> employees = Whitebox.getInternalState(department, "employees");
        assertTrue(employees.contains(employee));
    }
    
    
    @Test
    public void shouldAddNewEmployeeToTheDepartment() {
        
        final Department department = new Department();
        final Employee employee = new Employee();
        final ArrayList<Employee> employees = new ArrayList<Employee>();
        Whitebox.setInternalState(department, "employees", employees);
        department.addEmployee(employee);
        assertTrue(employees.contains(employee));
    }
    
    @Test
    public void shouldVerifyThatMaxSalaryOfferedForADepartmentIsCalculatedCorrectly() throws Exception
    {
        
        final Department department = new Department();
        final Employee employee1 = new Employee();
        final Employee employee2 = new Employee();
        employee1.setSalary(60000);
        employee2.setSalary(65000);
        //Adding two employees to the test employees list.
        final ArrayList<Employee> employees = new ArrayList<Employee>();
        employees.add(employee1);
        employees.add(employee2);
        Whitebox.setInternalState(department, "employees", employees);
        Whitebox.invokeMethod(department,"updateMaxSalaryOffered");
        final long maxSalary = Whitebox.getInternalState(department, "maxSalaryOffered");
        assertEquals(65000, maxSalary);
    }
}

 Whitebox.getInternalState(department, "employees")相似堆棧,查看變量的值。Whitebox.setInternalState(department, "employees",

employees)設置變量的值。 Whitebox.invokeMethod(department, "updateMaxSalaryOffered")調用方法。

更多參考:http://powermock.googlecode.com/svn/docs/powermock-1.5/apidocs/org/powermock/reflect/Whitebox.html。

 

ads_sms中測試手機號碼發送短信

package com.oppo.os.ads.sms.sevice;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.reflect.Whitebox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations="classpath:dubbo/ads-sms-svc.xml") 
public class SmsTaskTest {
    
    @Autowired
    SmsTask svc;

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void checkLimitOk() throws Exception {
        System.out.println("initAccUser");
        boolean result = Whitebox.invokeMethod(svc,"checkLimit", 6, "13246680798", 3, 20160121, 20160121);
        assertEquals(true, result);
    }

    @Test
    public void checkLimitFail() throws Exception {
        System.out.println("initAccUser");
        boolean result = Whitebox.invokeMethod(svc,"checkLimit", 0, "13246680998", 3, 20160121, 20160121);
        assertEquals(false, result);
    }
}

 

ads_ad 中的pom.xml配置:

        <dependency>    
            <groupId>org.powermock</groupId>    
            <artifactId>powermock-module-junit4</artifactId>    
            <version>1.6.3</version>    
            <scope>test</scope>    
        </dependency>        
        <dependency>    
            <groupId>org.powermock</groupId>    
            <artifactId>powermock-api-mockito</artifactId>    
            <version>1.6.3</version>    
            <scope>test</scope>    
        </dependency>    
        <dependency>
              <groupId>org.powermock</groupId>
              <artifactId>powermock-module-junit4-rule</artifactId>
              <version>1.6.3</version>
              <scope>test</scope>
        </dependency>        
        
        <dependency>
              <groupId>org.powermock</groupId>
              <artifactId>powermock-classloading-xstream</artifactId>
              <version>1.6.3</version>
              <scope>test</scope>
        </dependency>

測試文件:

package com.oppo.os.ads.ad.cpd.app.service;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.reflect.Whitebox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.mockito.Matchers.*;

import com.oppo.os.ads.ad.cpd.app.entity.AdsAdBid;

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations="classpath:dubbo/ad-cpd-app-svc.xml")
public class AdsAdAppBidSrvTest {
    
    //@Rule
    //public PowerMockRule rule = new PowerMockRule();

    @Autowired
    AdsAdAppBidSrv appSrvImpl;
    
    @Test
    public void testAccOutDayBudgetString() {
        appSrvImpl.accOutDayBudget("2839488");
    }

    @Test
    public void testAccOutDayBudgetInt() {
        appSrvImpl.accOutDayBudget(2839488);
    }

    @Test
    public void testOutDayBudget() {
        appSrvImpl.outDayBudget(5160);
    }

    @Test
    public void testBalanceInsufficientString() {
        appSrvImpl.balanceInsufficient("2839488");
    }

    @Test
    public void testBalanceInsufficientLong() {
        appSrvImpl.balanceInsufficient(2839488);
    }

    @Test
    public void testAddAd() {
        AdsAdBid bid = new AdsAdBid();
        bid.setId(5160L);
        appSrvImpl.addAd(bid);
    }

    @Test
    public void testUpdateAd() {
        AdsAdBid bid = new AdsAdBid();
        bid.setId(5160L);
        bid.setName("789798");
        appSrvImpl.updateAd(bid);
    }
    

    @Test
    public void testStartAd() {
        appSrvImpl.startAd(5160);
    }

    @Test
    public void testPauseAd() {
        AdsAdBid bid = new AdsAdBid();
        bid.setId(5160L);
        appSrvImpl.pauseAd(bid);
    }
    
    @Test
    public void testDeleteAdCache() throws Exception {

        Whitebox.invokeMethod(appSrvImpl,"deleteAdCache", "1001");
    }


}

 

 

禁用非預期行爲

新增類BaseEntity:

public class BaseEntity {

    static {
        String x = null;
        x.toString();
    }
    
    public BaseEntity() {
        throw new UnsupportedOperationException();
    }
    
    protected void performAudit(String auditInformation) {
        throw new UnsupportedOperationException();
    }
}

修改類Department:

public class Department extends BaseEntity {

    private int departmentId;
    private String name;
    
    public Department(int departmentId) {
        super();
        this.departmentId = departmentId;
    }
    
    public void setName(String name) {
        this.name = name;
        super.performAudit(this.name);
    }    
    
    protected void performAudit(String auditInformation) {
        throw new UnsupportedOperationException();
    }
    
    public Object getDepartmentId() {
        return departmentId;
    }
    
    public Object getName() {
        return name;
    }
}

修改類DepartmentTest:

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.junit4.PowerMockRunner;


@RunWith(PowerMockRunner.class)
@PrepareForTest(Department.class)
@SuppressStaticInitializationFor("BaseEntity")
public class DepartmentTest {
    
    @Test
    public void shouldSuppressTheBaseConstructorOfDepartment() {
        PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class));
        assertEquals(10, new Department(10).getDepartmentId());
    }
    
    @Test
    public void shouldSuppressThePerformAuditMethodOfBaseEntity() {
        PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class));
        PowerMockito.suppress(PowerMockito.method(BaseEntity.class, "performAudit", String.class));
        final Department department = new Department(18);
        department.setName("Mocking with PowerMock");
        assertEquals("Mocking with PowerMock", department.getName());
    }
    
    @Test
        public void shouldSuppressTheInitializerForBaseEntity() {
        
            PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class));
            assertNotNull(new Department(18));
    }
}

注意測試代碼並未試驗成功。

PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class));表示禁用BaseEntity的構造函數。PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class, String.class, Integer.class))後面表示帶字符串和整數參數。

PowerMockito.suppress(PowerMockito.method(BaseEntity.class, "performAudit", String.class))表示禁用BaseEntity的performAudit方法。

@SuppressStaticInitializationFor("BaseEntity")表示禁用BaseEntity的靜態初始化。注意引號部分一般須要全名,好比"com.gitshah.powermock.BaseEntity"。

PowerMockito.suppress(PowerMockito.field(BaseEntity.class,"identifier")):禁用域。

參考資料

簡明教程: https://github.com/jayway/powermock

https://github.com/jayway/powermock/wiki/MockitoUsage

https://www.ibm.com/developerworks/cn/java/j-lo-powermock/

 書籍:Instant Mock Testing with PowerMock

做者博客:http://my.oschina.net/u/1433482 python測試開發精華羣 291184506 PythonJava單元白盒測試 144081101

 

Powermock在Spring測試的應用

本部分先對spring作簡單介紹,而後介紹mockito和powermock在spring測試中的應用。

此部分須要準備的軟件:

基於JDK 7或以上版本

Eclipse   http://www.oracle.com/technetwork/java/javase/downloads/index.html
Mockito    http://mockito.org/
Spring     http://maven.springframework.org/release/org/springframework/spring/

Spring簡介


Spring是Java的開源企業應用程序開發框架,它爲 Java beans控制容器的翻轉。最初由Rod Johnson在2003年6月基於Apache2.0許可證發佈。
Spring框架處理底層,使咱們可以專一於應用程序邏輯。 Spring可以從POJOs(Plain Old Java Objects)非侵入式的構建應用程序。好比:
•不須要處理servlet或servlet API,Java方法能夠處理HTTP POST / GET請求。
•不須要處理web服務API,Java方法可提供RESTful Web服務
•不須要處理事務API,Java方法能夠執行數據庫事務
•不須要處理遠程API,本地Java方法使用RPC(remote procedure call)
•不須要處理JMS API,Java方法可使用和處理消息
•不須要處理JMX API,Java方法能夠做爲管理擴展

Spring的特性:
•開源應用程序框架
•企業輕量級應用框架
•非侵入性(基於POJO)
•模塊化
•可擴展用於其餘框架
•Java企業應用程序的事實標準

優點:
•使用POJO、輕,非入侵
•經過依賴注入和接口定向實現鬆耦合
•經過aspect和共同約定實現聲明式編程
•經過aspect和模板減小代碼

Spring Framework的核心容器:

•  Core and Beans:提供IOC(Inversion of control)和DI(dependency injection)

• Context:相似JNDI(Java Naming and Directory Interface,Java命名和目錄接口),用於在框架中訪問對象。

• 表示語言(Expression Language):SpEL,用於查詢和修改對象圖並評估數學表達式。

 

AOP模塊
AOP是Spring面向方面編程的實現。它解耦業務邏輯和日誌、安全等基礎代碼。

instrumentation模塊
提供instrumentation類支持,經過MBean展現容器資源和幫助JMX管理。

消息模塊
包含Spring Integration項目的關鍵抽象如Message、MessageChannel和的MessageHandler。


數據訪問模塊
•JDBC:JDBC抽象層
•ORM:爲流行的對象關係映射提供集成層API,包括JPA,JDO,Hibernate和iBATIS
•OXM:對象/ XML映射抽象層,實現了JAXB,Castor,XMLBeans的,JiBX和Xstream

•JMS:生產和消費消息
•事務:它支持programmatic和programmatic事務管理

web層
該網絡層包括web,webmvc / servlet中,WebSocket和webmvc-portlet模塊:

•Web:文件上傳等基礎組件。
•Webmvc:
•Portlet
•WebSocket

 

Spring項目涉及安全配置、Web應用程序、大數據、LDAP等。 Spring框架是其中一部分。
JNDI(Java Naming and Directory Interface,Java命名和目錄接口)

Java相關的一些博客:

http://www.gualtierotesta.it/

 

IoC(Inversion of Control)和DI(dependency injection)常常不區分使用。IoC由IoC實現。

兩種類型的依賴注入:

•  Constructor injection

•  Setter injection

 

好比定義:

<bean id="bookLister" class="com.packt.di.BookLister">
<constructor-arg ref="bookService"/>
</bean>
<bean id="bookService" class="com.packt.di.BookServiceImpl" />

等同於:

BookService service = new BookServiceImpl();
BookLister bookLister = new BookLister(service);

 

<bean id="bookListerSetterInjection" class="com.packt.di.BookLister">
<property name="bookService" ref="bookService" />
</bean>
<bean id="bookService" class="com.packt.di.BookServiceImpl" />

等同於:

BookService service = new BookServiceImpl();
BookLister bookLister = new BookLister();
bookLister.setBookService(service);

 

Spring IoC container 即ApplicationContext。管理的容器叫bean,好比bookService就是bean,即Spring IoC container管理的對象。

 

bean的屬性有:

class、name(即id)、scope、constructor-arg、properties、lazy-init(使用時才建立容器)、init-method 、destroy-method。

 

scope的取值有:

  • singleton:每一個bean實例一個容器。其實是每一個bean實例一個classloader。

  • prototype:每一個bean實例多個實例對象。

  • request:每一個bean實例一個HTTP request。

  • session:每一個bean實例一個HTTP session。

  • global-session:每一個bean實例一個全局HTTP session。

生命週期:

 

第一個實例

前提: Maven和STS安裝OK,均可以從Eclipse 市場安裝。

新建Spring Starter Project項目,

Name:SpringOverview 註明名字先後不要有空格。

Type:Maven

其餘用默認配置。

原有默認的SpringOverviewApplication類內容以下:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringOverviewApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringOverviewApplication.class, args);
    }
}

刪除包com.example下面的SpringOverviewApplication類。新建HelloWorld類:

package com.example;

public class HelloWorld {
    
    private String message;
    
    public String getMessage() {
        return message;
    }
    
    public void setMessage(String message) {
        this.message = message;
    }
}

在src/main/resources新建 applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="helloWorld" class="com.example.HelloWorld">
        <property name="message" value="Welcome to the Spring world">
        </property>
    </bean>
</beans>

com.example下面新建類HelloWorldExample:

package com.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloWorldExample {
    
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld world = (HelloWorld)
        context.getBean("helloWorld");
        System.out.println(world.getMessage());
        }
}

用Spring Boot App的方式執行:

11:38:15.765 [main] DEBUG o.s.core.env.StandardEnvironment - Adding [systemProperties] PropertySource with lowest search precedence
11:38:15.768 [main] DEBUG o.s.core.env.StandardEnvironment - Adding [systemEnvironment] PropertySource with lowest search precedence
11:38:15.768 [main] DEBUG o.s.core.env.StandardEnvironment - Initialized StandardEnvironment with PropertySources [systemProperties,systemEnvironment]
11:38:15.770 [main] INFO  o.s.c.s.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@71c7db30: startup date [Thu Dec 31 11:38:15 CST 2015]; root of context hierarchy
11:38:15.794 [main] DEBUG o.s.core.env.StandardEnvironment - Adding [systemProperties] PropertySource with lowest search precedence
11:38:15.795 [main] DEBUG o.s.core.env.StandardEnvironment - Adding [systemEnvironment] PropertySource with lowest search precedence
11:38:15.795 [main] DEBUG o.s.core.env.StandardEnvironment - Initialized StandardEnvironment with PropertySources [systemProperties,systemEnvironment]
11:38:15.801 [main] INFO  o.s.b.f.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
11:38:15.811 [main] DEBUG o.s.b.f.xml.DefaultDocumentLoader - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
11:38:15.830 [main] DEBUG o.s.b.f.xml.PluggableSchemaResolver - Loading schema mappings from [META-INF/spring.schemas]
11:38:15.833 [main] DEBUG o.s.b.f.xml.PluggableSchemaResolver - Loaded schema mappings: {http://www.springframework.org/schema/cache/spring-cache-4.2.xsd=org/springframework/cache/config/spring-cache-4.2.xsd, http://www.springframework.org/schema/aop/spring-aop-4.1.xsd=org/springframework/aop/config/spring-aop-4.1.xsd, http://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd, http://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-4.2.xsd, http://www.springframework.org/schema/aop/spring-aop-3.2.xsd=org/springframework/aop/config/spring-aop-3.2.xsd, http://www.springframework.org/schema/lang/spring-lang-4.1.xsd=org/springframework/scripting/config/spring-lang-4.1.xsd, http://www.springframework.org/schema/context/spring-context-4.0.xsd=org/springframework/context/config/spring-context-4.0.xsd, http://www.springframework.org/schema/beans/spring-beans-4.2.xsd=org/springframework/beans/factory/xml/spring-beans-4.2.xsd, http://www.springframework.org/schema/tool/spring-tool-4.1.xsd=org/springframework/beans/factory/xml/spring-tool-4.1.xsd, http://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd, http://www.springframework.org/schema/cache/spring-cache-3.2.xsd=org/springframework/cache/config/spring-cache-3.2.xsd, http://www.springframework.org/schema/jee/spring-jee-4.1.xsd=org/springframework/ejb/config/spring-jee-4.1.xsd, http://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd, http://www.springframework.org/schema/task/spring-task-4.2.xsd=org/springframework/scheduling/config/spring-task-4.2.xsd, http://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd, http://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-4.2.xsd, http://www.springframework.org/schema/cache/spring-cache-4.1.xsd=org/springframework/cache/config/spring-cache-4.1.xsd, http://www.springframework.org/schema/aop/spring-aop-4.0.xsd=org/springframework/aop/config/spring-aop-4.0.xsd, http://www.springframework.org/schema/jee/spring-jee-3.2.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd, http://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd, http://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd, http://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd, http://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd, http://www.springframework.org/schema/lang/spring-lang-4.0.xsd=org/springframework/scripting/config/spring-lang-4.0.xsd, http://www.springframework.org/schema/beans/spring-beans-4.1.xsd=org/springframework/beans/factory/xml/spring-beans-4.1.xsd, http://www.springframework.org/schema/tool/spring-tool-4.0.xsd=org/springframework/beans/factory/xml/spring-tool-4.0.xsd, http://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd, http://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd, http://www.springframework.org/schema/jee/spring-jee-4.0.xsd=org/springframework/ejb/config/spring-jee-4.0.xsd, http://www.springframework.org/schema/task/spring-task-4.1.xsd=org/springframework/scheduling/config/spring-task-4.1.xsd, http://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd, http://www.springframework.org/schema/cache/spring-cache-4.0.xsd=org/springframework/cache/config/spring-cache-4.0.xsd, http://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd, http://www.springframework.org/schema/util/spring-util-4.2.xsd=org/springframework/beans/factory/xml/spring-util-4.2.xsd, http://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd, http://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd, http://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-4.2.xsd, http://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframework/aop/config/spring-aop-3.0.xsd, http://www.springframework.org/schema/beans/spring-beans-4.0.xsd=org/springframework/beans/factory/xml/spring-beans-4.0.xsd, http://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-4.2.xsd, http://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd, http://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd, http://www.springframework.org/schema/task/spring-task-4.0.xsd=org/springframework/scheduling/config/spring-task-4.0.xsd, http://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd, http://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd, http://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd, http://www.springframework.org/schema/util/spring-util-4.1.xsd=org/springframework/beans/factory/xml/spring-util-4.1.xsd, http://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd, http://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd, http://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-4.2.xsd, http://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd, http://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd, http://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd, http://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-4.2.xsd, http://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd, http://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd, http://www.springframework.org/schema/context/spring-context-4.2.xsd=org/springframework/context/config/spring-context-4.2.xsd, http://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd, http://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd, http://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd, http://www.springframework.org/schema/util/spring-util-4.0.xsd=org/springframework/beans/factory/xml/spring-util-4.0.xsd, http://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd, http://www.springframework.org/schema/aop/spring-aop-4.2.xsd=org/springframework/aop/config/spring-aop-4.2.xsd, http://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-4.2.xsd, http://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd, http://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd, http://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd, http://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-4.2.xsd, http://www.springframework.org/schema/lang/spring-lang-4.2.xsd=org/springframework/scripting/config/spring-lang-4.2.xsd, http://www.springframework.org/schema/context/spring-context-4.1.xsd=org/springframework/context/config/spring-context-4.1.xsd, http://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd, http://www.springframework.org/schema/tool/spring-tool-4.2.xsd=org/springframework/beans/factory/xml/spring-tool-4.2.xsd, http://www.springframework.org/schema/jee/spring-jee-4.2.xsd=org/springframework/ejb/config/spring-jee-4.2.xsd, http://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.2.xsd}
11:38:15.833 [main] DEBUG o.s.b.f.xml.PluggableSchemaResolver - Found XML schema [http://www.springframework.org/schema/beans/spring-beans.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-4.2.xsd
11:38:15.862 [main] DEBUG o.s.b.f.x.DefaultBeanDefinitionDocumentReader - Loading bean definitions
11:38:15.871 [main] DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from location pattern [applicationContext.xml]
11:38:15.872 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext@71c7db30: org.springframework.beans.factory.support.DefaultListableBeanFactory@4d95d2a2: defining beans [helloWorld]; root of factory hierarchy
11:38:15.888 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@11758f2a]
11:38:15.889 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@4671e53b]
11:38:15.890 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4d95d2a2: defining beans [helloWorld]; root of factory hierarchy
11:38:15.890 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'helloWorld'
11:38:15.890 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'helloWorld'
11:38:15.898 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'helloWorld' to allow for resolving potential circular references
11:38:15.914 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'helloWorld'
11:38:15.915 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@2f8f5f62]
11:38:15.915 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
11:38:15.917 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
11:38:15.917 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.liveBeansView.mbeanDomain' in [systemProperties] with type [String] and value ''
11:38:15.919 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'helloWorld'
Welcome to the Spring world

生命週期信息

ApplicationContextAware:實現setApplicationContext方法。
BeanNameAware:實現setBeanName方法。
InitializingBean:實現InitializingBean方法。
BeanFactoryAware:實現setBeanFactory方法。
BeanPostProcessor:實現postProcessBeforeInitialization和postProcessAfterInitialization方法。
DisposableBean:實現destroy方法。

在HelloWorld類中添加以下方法:

    public void myInit() {
        System.out.println("custom myInit is called ");
    }
    
    public void myDestroy() {
        System.out.println("custom myDestroy is called ");
    }

     
    
修改xml文件:
 

<bean id="helloWorld" class="com.packt.lifecycle.HelloWorld"
init-method="myInit" destroy-method="myDestroy">
<property name="message" value="Welcome to the Spring world">
</property>
</bean>

修改HelloWorldExample類
 

    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld world = (HelloWorld) context.getBean("helloWorld");
        context.getBean("helloWorld");
        System.out.println(world.getMessage());
        context.registerShutdownHook();
    }

    
如今執行能夠看到「custom myInit is called 」等信息。

autowiring和註解


Spring容器能夠自動處理bean之間的依賴關係,這樣就不必使用 <constructor-arg>和 <constructor-arg>標籤,簡化了應用程序上下文XML配置。
autowiring的類型以下:
•no:默認沒有。
•byName:使用配置文件中相同名字的beans定義。
•byType的:使用配置文件中相同屬性的beans定義。若是有多個則拋出異常。
•constructor:相似type,但基於構造類型。
•default:先使用constructor,不成功則基於byType。

修改applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    ">
    <context:annotation-config/>
       <bean name="message" id="message" class="java.lang.String">
           <constructor-arg value="auto wired" />
    </bean>
    
    <bean id="helloWorld" class="com.example.HelloWorld">
    </bean>
       
</beans>

註解類型以下:
•@Required:該註釋適用於bean的setter方法
•@Autowired:bean的setter方法,構造函數和屬性
•@Qualifier:和@Autowired一塊兒用於限定bean。
經過<context:annotation-config/>開啓autowiring的註解。

修改HelloWorld:

package com.example;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class HelloWorld implements ApplicationContextAware,BeanNameAware, InitializingBean,
        BeanFactoryAware,BeanPostProcessor,  DisposableBean {
    
    @Autowired
    private String message;
    public String getMessage() {
        return message;
    }
    
    @Autowired
    public void setMessage(String message) {
        this.message = message;
    }    
    
    
    public void setBeanName(String arg0) {
        System.out.println("setBeanName is called with " + arg0);
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet is called ");
    }
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out.println("setBeanFactory is called ");
    }
    public void myInit() {
        System.out.println("custom myInit is called ");
    }
    public void myDestroy() {
        System.out.println("custom myDestroy is called ");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("destroy is called ");// TODO Auto-generated method stub
    }
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {
        System.out.println("postProcessAfterInitialization is called with "+arg0+" and "+arg1);
        return null;
    }
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {
        System.out.println("postProcessBeforeInitialization is called with "+arg0+" and "+arg1);
        return null;
    }
    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        System.out.println("setApplicationContext is called ");    
    }
}

如今執行能夠看到"auto wired"信息。

aspect


AOP是Spring框架的關鍵組件之一。面向對象編程不能很好地處理一些通用功能。好比:
•日誌記錄和跟蹤
•事務管理
•安全
•緩存
•錯誤處理
•性能監控
•自定義業務規則
•事件處理

AOP覆蓋OOP的數據驅動層,用AspectJ和Spring AOP的實現:
•AspectJ:這是原來的AOP技術(從第一個版本的日期1995開始),提供了全面的,面向方向的編程語言,使用字節碼修改。
•Spring AOP的:基於Java的AOP框架,它使用動態代理,主要用來解決企業級問題。

•Join point鏈接點:插入邏輯的鏈接點。一般在:
°方法調用
°類初始化
°對象初始化
•Advice建議:鏈接點執行的代碼。3種以下:
°before。
°after。
°around(兼具before和after的功能。
•Pointcut切入點:鏈接點的集合,一般是多個實際Join point的執行點。
•Aspect切面:實現橫切,鏈接advice和Pointcut。一個應用能夠有
任何數目的方面的,根據不一樣的要求。
•Weaving編織:應用到代碼的過程,有三種類型:
°編譯時
°類加載
°運行時

•目標:
•簡介:修改該結構,引入額外的方法或字段。

有兩種類型的AOP:
•靜態AOP
°weaving是構建過程當中的另外一個步驟
°例如Java程序,能夠過改變和修改應用程序的實際字節碼
•動態AOP
°weaving在運行時動態地進行
°很容易改變的weaving過程而無需從新編譯
Spring AOP是基於代理。關於代理的更多資料: http://en.wikipedia.org/wiki/Proxy_pattern,下面咱們作個簡單的演示:

建立接口IMessageWriter:

package com.example;
public interface IMessageWriter {
    void writeMessage();
}

MessageWriter類實現IMessageWriter:

package com.example;
public class MessageWriter implements IMessageWriter {
    
    @Override
    public void writeMessage() {
        System.out.print("World");
    }
}

調用 writeMessage()是鏈接點。咱們想把「World」把改爲「 Hello World !」。MethodInterceptor是AOP標準接口。新建類MessageDecorator:

package com.example;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MessageDecorator implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.print("Hello ");
        Object retVal = invocation.proceed();
        System.out.println("!");
        return retVal;
    }
}

AOPTest類使用ProxyFactory類建立代理:

package com.example;
import org.springframework.aop.framework.ProxyFactory;
public class AOPTest {
    public static void main(String[] args) {
        MessageWriter target = new MessageWriter();
        // create the proxy
        ProxyFactory pf = new ProxyFactory();
        // Add the given AOP Alliance advice to the tail
        // of the advice (interceptor) chain
        pf.addAdvice(new MessageDecorator());
        // Set the given object as target
        pf.setTarget(target);
        // Create a new proxy according to the
        // settings in this factory
        MessageWriter proxy = (MessageWriter) pf.getProxy();
        // write the messages
        target.writeMessage();
        System.out.println("");
        // use the proxy
        proxy.writeMessage();
    }
}

 

Spring JDBC


Spring Data Access Object (DAO)支持統一的方式訪問JDBC, Hibernate或JDO。Spring還能夠處理異常,轉換爲未檢查或者運行時。
DAO支持類以下:
•  JdbcDaoSupport
•  HibernateDaoSupport
•  JdoDaoSupport
•  JpaDaoSupport

一般的JDBC訪問數據庫代碼以下:
1.定義鏈接參數。
2.打開鏈接。
3.指定的語句。
4.準備和執行該語句。
5.設置循環遍歷結果(若是有的話)。
6.處理每一個迭代。
7.處理異常。
8.處理事務。
9.關閉鏈接。

Spring簡化爲以下:
1.指定語句。
2.處理每一個迭代。

Spring-JDBC事務框架包含以下包:
•  org.springframework.jdbc.core
•  org.springframework.jdbc.datasource
•  org.springframework.jdbc.object
•  org.springframework.jdbc.support

org.springframework.jdbc.core包含以下類:
•  JdbcTemplate
•  不一樣的回調接口
•  其餘相關類

org.springframework.jdbc.datasource包有如下類:
•便於數據源訪問的工具類
•各類簡單的DataSource實現,用於在J2EE容器以外測試和運行未修改的JDBC代碼
•utility類提供靜態方法從JNDI得到鏈接和必要時關閉鏈接。
•支持綁定線程的鏈接,例如DataSourceTransactionManager

org.springframework.jdbc.object包含如下內容:
•線程安全並可重用的數據庫查詢,更新和存儲過程類
•這種方法是經過JDO模型,查詢對象與數據庫斷開鏈接
•JDBC的高層抽象依賴於底層抽象org.springframework.jdbc.core。

該org.springframework.jdbc.support包包含如下內容:
•SQLException的轉換功能和一些工具類
•轉換異常
•使用Spring JDBC抽象層的代碼不須要實現JDBC-或者RDBMS特定的錯誤處理
•全部unchecked異常。

JdbcTemplate類是org.springframework.jdbc.core的主類。它處理了資源建立和釋放,簡化了JDBC的使用。這有助於避免通用錯誤,如不關閉鏈接。它執行核心JDBC工做流,如語句建立和執行。

 

TestContext框架介紹



Spring的TestContext框架是一個通用的,註解驅動的框架,用於單元測試和集成測試。框架的資源位於org.springframework.test.context包,約定優於配置,每一個配置都有默認值,經過註解能夠修改非約定的配置。支持JUnit和TestNG,好比能夠自定義JUnit執行器來支持非入侵的POJO測試類。

框架包含的類以下:
•TestContext: 該類提供在測試執行的上下文和上下文管理和緩存支持。加載應用程序上下文使用ContextLoader或SmartContextLoader接口。
•TestContextManager:框架的主入口點。它管理單個TestContext類和發佈事件到TestExecutionListener實現。

這是測試執行要點:
°在靜態類方法以前,
°在測試執行方法以前,
°在測試實例的準備
°測試執行方法以後
°在靜態類方法以後

如下是接口:
•TestExecutionListener
•ContextLoader:這個接口加載集成測試的ApplicationContext
•SmartContextLoader:擴展ContextLoader接口,在Spring3.1引入,處理資源位置,註解類,或上下文初始化,還能夠設置 active bean profiles ( @ActiveProfiles )和屬性資源。

每一個測試有一個TestContextManager類,它管理TestContext並處理 dependency injection, dirty checks, transactional support等。TestContextManager委派TestExecutionListener(經過dependency injection,managing transactions實現實際的測試執行)。

默認TestExecutionListener的實現方式註冊方式以下:
• ServletTestExecutionListener: WebApplicationContext的Servlet API mock。
• DependencyInjectionTestExecutionListener
• DirtiesContextTestExecutionListener:檢查上下文,確實測試執行時是否有髒bean。它還處理@DirtiesContext註解。
• TransactionalTestExecutionListener:這提供了事務性支持
•SqlScriptsTestExecutionListener:經過@sql註解執行SQL腳本

 

自定義TestExecutionListener

新建Spring maven新工程SpringTests。

新建類SpringTestsApplication:

package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;

public class SysOutTestExecutionListener implements TestExecutionListener {
    
    @Override 
    public void afterTestClass(TestContext testContext) throws Exception {
        ApplicationContext ctx = testContext.getApplicationContext();
        System.out.println("In afterTestClass for class = " + testContext.getTestClass());
    }
    
    @Override 
    public void afterTestMethod(TestContext testContext) throws Exception {
        System.out.println("In afterTestMethod for = " + testContext.getTestMethod().getName());
    }
    
    @Override public void beforeTestClass(TestContext testContext) throws Exception {
        System.out.println("In beforeTestClass for class = " + testContext.getTestClass());
    }
    
    @Override public void beforeTestMethod(TestContext testContext) throws Exception {
        System.out.println("In beforeTestMethod for =" + testContext.getTestMethod().getName());
    }
    @Override
    public void prepareTestInstance(TestContext testContext) throws Exception {
        System.out.println("In prepareTestInstance for= " + testContext.getTestInstance());
    }
}

 

新建類:

package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
@TestExecutionListeners({SysOutTestExecutionListener.class})
public class TestExecutionListenerTest {
    
    @Test
    public void someTest() throws Exception {
        System.out.println("executing someTest");
    }
    
    @Test
    public void someOtherTest() throws Exception {
        System.out.println("executing someOtherTest");
    }
}


新建文件:SpringTests/src/main/resources/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    ">
</beans>

另有註冊多個監聽器和設置默認值的方法,暫時沒有試驗,請參見:Mockito for Spring - 2015

 

配置Spring profile

Spring3.1引入了profile。它能夠把一個包能夠部署在各類環境中,如開dev, test, prod, perf等。
定義的系統屬性spring.profiles.active,或使用 @ActiveProfiles註解測試類便可。

修改: applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
       
    <bean name="noProfileBean" id="message"
        class="java.lang.String">
        <constructor-arg value="I'm a free bean" />
    </bean>     
    
    <beans profile="dev">
        <bean name="message" id="message" class="java.lang.String">
            <constructor-arg value="I'm a dev bean" />
        </bean>
    </beans>  
 
     <beans profile="prod">
        <bean name="message" id="message" class="java.lang.String">
        <constructor-arg value="I'm a prod bean" />
        </bean>
    </beans>
 
</beans>

新建測試類:

package com.example;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
@ActiveProfiles(profiles={"dev"})
public class ProfileTest {
    
    @Autowired
    ApplicationContext context;
    
    @Test
    public void profile() throws Exception {
        assertEquals("I'm a dev bean", context.getBean("message"));
        //assertEquals("I'm a free bean", context.getBean("noProfileBean"));
    }
}

除了ActiveProfiles註解,也能夠在環境變量中指定。好比spring.profiles.active = dev。

環境mock

後面補充

JNDI查找mock

後面補充

ReflectionTestUtils

org.springframework.test.util包的ReflectionTestUtils類包含很多反射方法,如設置非公開域或調用private/protected的setter方法等。
以下:
•ORM框架,如JPA和Hibernate
•Spring的註解支持,如@Autowired,@Inject,和@Resource,這對於private/protected域的提供依賴注入,setter方法和配置方法。

下面的示例演示ReflectionUtils的功能:
新增方法:Secret

package com.example;

public class Secret {
    
    private String secret;
    public void initiate(String key) {
        this.secret = key.replaceAll("a", "z").replaceAll("i", "k");
    }
}

測試代碼

package com.example;

import static org.junit.Assert.*;
import java.lang.reflect.Field;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;

public class ReflectionUtilsTest {
    
    @Test
    public void private_field_access() throws Exception {
        
        Secret myClass = new Secret();
        myClass.initiate("aio");
        Field secretField = ReflectionUtils.findField(Secret.class, "secret", String.class);
        assertNotNull(secretField);
        ReflectionUtils.makeAccessible(secretField);
        assertEquals("zko", ReflectionUtils.getField(secretField, myClass)); 
        ReflectionUtils.setField(secretField, myClass, "cool");
        assertEquals("cool", ReflectionUtils.getField(secretField, myClass));
    }
}

 

 

 

 

 

 

 

public interface MyInterface {

    // constant definition
    String URL = "http://www.vogella.com";

    // public abstract methods
    void test();
    void write(String s);
    
    // default method
    default String reserveString(String s){
      return new StringBuilder(s).reverse().toString();
    }
}
public class MyClassImpl implements MyInterface {
    @Override
    public void test() {
    }
    @Override
    public void write(String s) {
    }
  
    public static void main(String[] args) {
        MyClassImpl impl = new MyClassImpl();
        System.out.println(impl.reserveString("Lars Vogel"));
    }
}
public interface A {
  default void m() {}
}

public interface B {
  default void m() {}
}
    
public class C implements A, B {
  @Override
  public void m() {}
}
public class C implements A, B {
  @Override
  public void m() {A.super.m();}
}

  

註解                

註解有運行時(RetentionPolicy.RUNTIME)和開發時(RetentionPolicy.SOURCE)兩種。       

重寫方法和@Override 註解

若是一個類繼承另外一個類,它會繼承父類的方法。若是它想要改變父類的一些方法,可重寫這些方法。能夠在子類中用相同的方法簽名重寫父類方法。

你可使用 @Override 註解明確告訴後續的維護代碼的程序員以及 Java 編譯器,重寫了父類對應方法。

 

@Deprecated表示不推薦使用。                

Java 8提供了類型註解,好比:

    

@NonNull String name;
List<@NonNull String> names;
class UnmodifiableList<T> implements @Readonly List<@Readonly T> {...}
email = (@Email String) input;
new @Information MyObject();
void doSomething() throws @ImportantForMe MyException { ... }

 

下面的代碼演示瞭如何重寫父類的方法:            

MyBaseClass.java:

class MyBaseClass {

  public void hello() {
    System.out.println("Hello from MyBaseClass");
  }
}

MyExtensionClass2.java:

class MyExtensionClass2 extends MyBaseClass {
  
  @Override                
  public void hello() {
    System.out.println("Hello from MyExtensionClass2");
  }
}

最好始終在重寫父類方法時使用 @Override 註解,這樣編譯機能夠幫助開發人員檢查是否正確的重寫了父類中對應的方法。

變量和方法

原始數據類型和應用

Java 中主要有兩大類類型,原始類型(好比:boolean、short、int、double、float、char 以及 byte)和引用類型(好比:Object 和 String)。

       

原始數據類型

原始數據類型變量用來描述:數字、布爾值(true/false) 或者字符。原始類型變量不是    對象,所以不能經過這些變量執行方法調用。

*,-,+,/只能在原始類型上使用,不過 + 能夠在字符串上使用,表明字符串拼接。

 

int  –2.14 billion to 2.14 billion
float    decimal numbers of up to 38 figures
double     decimal numbers up to 300 figures
character 單個字符
string
byte    –128 to 127
short     –32,768 to 32,767
long    –9.22 quintillion to 9.22 quintillion

 

long salary = 264_400_000; java 7 支持。
變量名: 字母、下劃線或者美圓符號開頭。



指明數值類型:
float pi = 3.14F;
沒有F默認是double,L對應long integer, D對應float。
 

 

引用類型

引用類型變量表明到一個對象的引用(或者指針)。若是你修改引用類型變量的值,那麼這個變量會指向性的對象或者 nullnull表明空引用或者引用到一個不存在的對象。修改應用對象變量並不會修改它指向的對象。修改指向對象的內容也不會影響指向它的引用。

類型自動裝箱(Autobox)和拆箱(Wrapper)

每個原始類型都有對應的引用類型(或者說對應的類)。這些引用類型能夠在一個對象中保存對應的原始類型。好比:java.lang.Integer 和 int。

將原始類型轉換到一個引用類型的實例或者相反的過程稱之爲:裝箱和拆箱。Java 會在必要的狀況下自動執行這些過程。這容許你在調用參數爲對象的方法時傳遞原始類型,這個過程稱之爲自動裝箱。        

變量

Java 程序在運行過程當中使用變量來保存過程值。變量能夠是原始類型也可使引用類型。原始類型變量保存對應的值,而引用類型變量保存的是對象的引用(指針)。所以,若是你比較兩個引用類型變量,你其實是在比較兩個引用類型變量是否指向同一個對象。所以,比較對象時須要使用 object1.equals(object2) 。

實例變量

實例變量定義在對象一級,在對象生命週期內均可以訪問。實例變量能夠賦予任何訪問控制而且能夠被標註爲 final 或者 transient

被標註爲 final 的實例變量在被賦值後是不能被改變的(實際就是隻能被賦值一次)。一般狀況下,final變量有3個地方能夠賦值:直接賦值,構造函數中,或是初始化塊中。

因爲在java的語法中,聲明和初始化是聯繫在一塊兒的,也就是說:若是你不顯示的初始化一個變量,系統會自動用一個默認值來對其進行初始化(如 int就是0)。對於final變量,在聲明時,若是你沒有賦值,系統默認這是一個空白域,在構造函數進行初始化,若是同時也是是靜態的 (static),則能夠在初始化塊賦值。

局部變量(Local variable)

局部變量不能賦予除 final 之外的訪問控制修飾,final 修飾的局部變量在賦值後不能夠被改變。

局部變量不會分配默認值,所以須要在使用前初始化它們。        

方法

方法是具有參數表以及返回值的代碼塊,須要經過對象來調用方法,下面是一個 tester 方法的定義:

MyMethodExample.java:

public class MyMethodExample {
  void tester(String s) {
    System.out.println("Hello World");
  }
}

方法能夠定義可變參數(var-args),定義類可變參數的方法能夠接受0個或者多個值(語法:type ... name;,一個方法只能定義一個可變參數,並且必須是方法參數表的最後一個參數定義。

重寫父類方法:子類方法須要與父類方法有徹底相同個數和類型的參數以及相同類型的返回值。

重載方法:重載方法是指多個方法有相同的方法名,可是有不一樣個數或類型參數,返回類型不一樣不能區分重載方法。

主方法(Main method)

具備 public static 簽名的方法能夠用來啓動 Java 應用程序(主入口),這個方法一般是 main 方法

public static void main(String[] args) {

}

構造函數(Constructor)

類包含它的構造函數,構造函數式在類構造時被調用的方法(執行 new SomeClass 時調用)。構造函數的聲明方式與方法相似,惟一的要求就是構造函數名必須與類名相同且不準定義返回類型。

類能夠有多個重載的構造函數,參考上一節對重載的描述。每個類須要有至少一個構造函數。下面構造函數代碼示例:

MyConstructorExample2.java:    

public class MyConstructorExample2 {

  String s;

  public MyConstructorExample2(String s) {
    this.s = s;
  }
}

 

若是代碼中沒有明確編寫構造函數,編譯器會在編譯期間隱式添加一個,若是一個類繼承與其餘類,那麼父類的構造函數會被隱式調用。

下面的例子中不須要定義一個無參的空構造函數,若是類中沒有定義構造函數,那麼編譯器會在編譯期間爲你定義一個構造函數:

MyConstructorExample.java:

public class MyConstructorExample {

  // unnecessary: would be created by the compiler if left out
  public MyConstructorExample() {
  }    
}

 

構造函數的命名約定是: classname (Parameter p1, ...) { }。每個對象是基於構造函數建立的,構造函數是對象可使用以前被調用的第一個方法。   

如下部分來自Java24_6th_ch11

Virus.java

public class Virus {
    static int virusCount = 0;

    public Virus() {
        virusCount++;
    }

    static int getVirusCount() {
        return virusCount;
    }
}

VirusLab.java

public class VirusLab {
    public static void main(String[] args) {
        int numViruses = Integer.parseInt(args[0]);
        if (numViruses > 0) {
            Virus[] virii = new Virus[numViruses];
            for (int i = 0; i < numViruses; i++) {
                virii[i] = new Virus();
            }
            System.out.println("There are " + Virus.getVirusCount()
                + " viruses.");
        }
    }
}

 

修飾符(Modifiers)

訪問控制修飾符

有三個用於訪問控制的關鍵字: publicprotected 和 private

和 4 種訪問控制級別:publicprotecteddefault 以及 private,這些級別用來定義元素對其餘組件的可見性。

若是某些元素被聲明爲 public。好比:類或者方法,那麼它們能夠由其它 Java 對象建立或訪問。若是某些元素被聲明爲 private,好比一個方法,那麼這個方法就只能被定義它的類中的元素訪問。

訪問級別 protected 和 default 很類似,一個 protected 的類只能被同一個包中的類或者它的子類(同一個包或者其餘包)訪問,default 訪問級別的類只能被同一個包中的類訪問。

下表是訪問級別的總結。    

表1. 訪問級別

修飾符 子類 全局
public Y Y Y Y
protected Y Y Y N
no modifier Y Y N N
private Y N N N

其餘修飾符

  • final 方法:不能夠被子類重寫

  • abstracct 方法:抽象方法,沒有實現的方法

  • synchronized 方法:線程安全的方法,能夠是 final 方法以及賦予其餘任何訪問控制

  • native 方法:這種方法用來編寫平臺相關代碼(好比:針對 Linux、Windows或Mac OS X等特定操做系統的本地代碼)

  • strictfpstrictfp 關鍵字可應用於類、接口或方法。使用 strictfp 關鍵字聲明一個方法時,該方法中全部的 float和 double表達式都嚴格遵照FP-strict的限制,符合IEEE-754規範。當對一個類或接口使用 strictfp 關鍵字時,該類中的全部代碼,包括嵌套類型中的初始設定值和代碼,都將嚴格地進行計算。嚴格約束意味着全部表達式的結果都必須是 IEEE 754 算法對操做數預期的結果,以單精度和雙精度格式表示。

 

import語句

使用 import 語句

在 Java 開發中咱們須要使用類的全名來訪問類,好比:cn.4byte.some_package.SomeClass。

你能夠在類中使用 import 語句引入一些類或包,這樣你在類中能夠不用使用全名稱來訪問引入的類。

靜態導入

static import 特性可讓咱們在類中使用公共靜態類( public static 定義的類)中的成員(方法、屬性),而不須要在使用時指定定義成員的類。

該功能提供了一種類型安全的機制,讓咱們在代碼中使用常量,而沒必要引用最初定義的常量的類。

更多的java語言結構        

類方法和類變量

與實例方法和實例變量不一樣,類方法和類變量是關聯類的。須要使用 類名+'.'+方法名或變量名的方式訪問類方法和類變量,如:SomeClass.someMethod 或者 SomeClass.someVariable

類方法和類變量須要使用 static 關鍵字來定義,類方法一般稱爲靜態方法,類變量一般稱爲靜態變量或者靜態屬性。

類變量的一個例子就是使用 System.out.println("Hello World") 調用 println 函數,這裏的 out 就是一個靜態域(靜態變量),它是 PrintStream 的實例,咱們經過它來調用 println 方法。

當你定義類變量後,Java 運行時環境在加載類時就會會爲類變量分配固定的內存以及訪問地址,所以不管類有多少個實例它的類變量始終指向相同的內存地址。咱們能夠將類變量理解爲全局變量。下面的代碼演示如何使用 static 域:

MyStaticExample.java    

public class MyStaticExample {
    
  static String PLACEHOLDER = "TEST";
      
  static void test() {
    System.out.println("Hello");
  }
}

Main.java:

public class Tester {
    
  public static void main(String[] args) {
    System.out.println(MyStaticExample.PLACEHOLDER);
    MyStaticExample.test();
  }
}

若是想要將變量定義爲常量,可使用 static final 關鍵字聲明這個變量。

靜態方法只能經過類來訪問,不可使用類的實例訪問,它不能直接訪問類中的非靜態變量和方法。

抽象類和抽象方法

    類以及方法能夠被聲明爲抽象的 abstract。若是一個類包含至少一個抽象方法(只有方法聲明,沒有方法實現)那麼這個類就是一個抽象類,它也須要使用 abstract 關鍵字聲明,而且這個類是不可以被直接實例化的。抽象類的子類須要實現抽象類中的抽象方法,除非子類也是抽象類。

    下面是抽象類定義的代碼示例:

MyAbstractClass.java:

public abstract class MyAbstractClass {
  abstract double returnDouble();
}

類中類

如下部分來自Java24_6th_ch11

下面Wrecker.java編譯後生成 Wrecker.class和VirusCode.class。

public class Wrecker {
    String author = 「Ignoto」;
    
    public void infectFile() {
        VirusCode vic = new VirusCode(1024);
    }
}

class VirusCode {
    int vSize;
    
    VirusCode(int size) {
        vSize = size;
    }
}

下面Wrecker.java編譯後生成 Wrecker.class和Wrecker$VirusCode.class。

public class Wrecker {
    String author = 「Ignoto」;
    
    public void infectFile() {
        VirusCode vic = new VirusCode(1024);
    }
    
    class VirusCode {
        int vSize;
        
        VirusCode(int size) {
            vSize = size;
        }
    }
}

 

備忘清單                    
    

使用類

在 Java 開發中你須要編寫不少的類、方法、和實例變量,下面的代碼使用 test 做爲包名。

表格2 

What to do How to do it
建立MyNewClass類
package test;

public class MyNewClass {

}

建立 var1 變量

package test;

public class MyNewClass {
  private String var1;
}
建立構造函數,爲 var1 賦值
package test;
public class MyNewClass {

  private String var1;
  
  public MyNewClass(String para1) {
    var1 = para1;
    // or this.var1= para1;
  }
}
建立doSomeThing方法
package test;
public class MyNewClass {

  private String var1;
  
  public MyNewClass(String para1) {
    var1 = para1;
    // or this.var1= para1;
  }
  
  public void doSomeThing() {
  }
}

 

建立doSomeThing2方法
package test;
public class MyNewClass {

  private String var1;
  
  public MyNewClass(String para1) {
    var1 = para1;
    // or this.var1= para1;
  }
  
  public void doSomeThing() {
  }
  
  public void doSomeThing2(int a, Person person) {
  }
}

建立doSomeThing3方法。

package test;
public class MyNewClass {

  private String var1;
  
  public MyNewClass(String para1) {
    var1 = para1;
    // or this.var1= para1;
  }
  
  public void doSomeThing() {
  }
  
  public void doSomeThing2(int a, Person person) {
  }
  
  public int doSomeThing3(String a, String b, Person person) {
    return 5; // any value will do for this example
  }
}
建立 MyOtherClass 類,以及兩個屬性 myvalue 和 dog及其set和get。
package test;
public class MyOtherClass {

  String myvalue;
  Dog dog;
  
  public String getMyvalue() {
    return myvalue;
  }
  
  public void setMyvalue(String myvalue) {
    this.myvalue = myvalue;
  }
  
  public Dog getDog() {
    return dog;
  }
  
  public void setDog(Dog dog) {
    this.dog = dog;
  }
}

this表示當前對象,這種方式引用變量可讀性更好。

使用局部變量

局部變量只能在方法中定義

表格3

目的 實現
建立 String 類型的局部變量 String variable1;
建立 String 類型的局部變量,並賦值 "Test" String variable2 = "Test";
建立 Person 類型的局部變量 Person person;
建立 Person 類型的局部變量,並建立 Person 對象賦值給它 Person person = new Person();
建立字符串數組 String array[];
建立 Person 數組並指定數組長度爲 5 Person array[]= new Person[5];
建立局部變量 var1 賦值 5 var1 = 5;
將 pers1 指向 pers2  pers1 = pers2;
建立 ArrayList 元素類型爲 Person ArrayList<Person> persons;
建立新的 ArrayList 並賦值給 persons persons = new ArrayList<Person>();
建立 ArrayList 元素類型爲 Person,並實例化 ArrayList<Person> persons = new ArrayList<Person>();

集成開發環境(IDE)

前面的章節介紹瞭如何在Shell(命令行)中建立和編譯 Java 應用程序。 Java集成開發環境(IDE)提供了大量用於建立Java程序的易用功能。有不少功能豐富的 IDE 好比:Eclipse IDE                

更多的信息能夠參考 教程

術語 「建立一個 Java 項目(Create a Java project)」在這裏能夠理解爲在 Eclipse 中建立一個 Java 項目。

練習:建立 Java 對象和方法

建立 Person 類而且實例化它

  • 建立一個 Java 項目叫 exercises1 而且使用 com.vogella.javastarter.exercises1 做爲包名。

  • 建立 Person 類,而且爲這個類增長三個實例變量:firstNamelastName 和 age

  • 使用Person的構造函數設置默認值。

  • 添加下面的toString方法並完善TODO內容,用於轉換對象爲字符串表示。

@Override
public String toString() {
    // TODO replace "" with the following:
    // firstName + " " + lastName
  return ""; 
}
  • 建立 Main 類,並定義方法 public static void main(String[] args),在這個方法中建立 Person 類的實例。

使用構造函數

爲你的 Person 類添加構造函數,構造函數定義兩個參數用來傳遞 first name 和 last name。並將這兩個參數的值賦給對應的實例變量。

定義 getter 和 setter 方法    

定義用來讀取和設置實例變量值的方法,這些方法被稱爲 getter 和 setter 方法。

Getter 方法命名方式是: get+實例變量名(實例變量名首字符須要大寫)好比:  getFirstName()

Setter 方法命名方式是:set+實例變量名(實例變量名手字符須要大寫)好比:setFirstName(String value)

修改 main 方法,使用 getter 和 setter 方法修改 Person 對象的 last name字段。

建立 Address 對象

建立Address 類用來保存 Person 的地址。    

        在 Person 對象中增長一個新的 Address 類型實例變量,以及對應的 getter 和 setter 方法。

答案:建立 Java 對象以及方法  

建立 Person 類並實例化

Person.java:

package exercises.exercise04;

class Person {

  String firstname = "Jim";
  String lastname = "Knopf";
  int age = 12;
          
  @Override
  public String toString() {
    return firstName + " " + lastName;
  }
}

 

Main.java:

package exercises.exercise04;
public class Main {

  public static void main(String[] args) {
    Person person = new Person();
    
    //  this calls the toString method on the pers object
    System.out.println(person);
  }
}

使用構造函數    

package com.vogella.javastarter.exercises1;

class Person {

  String firstName;
  String lastName;
  int age;
  
  public Person(String a, String b, int value) {
    firstName = a;
    lastName = b;
    age=value;
  }
  
  @Override
  public String toString() {
    return firstName + " " + lastName;
  }
}

        

Main.java:

package com.vogella.javastarter.exercises1;
public class Main {

  public static void main(String[] args) {
  
    Person p1 = new Person("Jim", "Knopf" , 12);
    System.out.println(p1);
    // reuse the same variable and assign a new object to it
    Person p2 = new Person("Henry", "Ford", 104);
    System.out.println(p2);
  }
}

 

定義 getter 和 setter 方法

package com.vogella.javastarter.exercises1;

class Person {

  String firstName;
  String lastName;
  int age;
  
  public Person(String a, String b, int value) {
    firstName = a;
    lastName = b;
    age = value;
  }
  
  public String getFirstName() {
    return firstName;
  }
  
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  
  public String getLastName() {
    return lastName;
  }
  
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  
  public int getAge() {
    return age;
  }
  
  public void setAge(int age) {
    this.age = age;
  }
  
  @Override
  public String toString() {
    return firstName + " " + lastName;
  }
}

 

Main.java:

package com.vogella.javastarter.exercises1;

public class Main {

  public static void main(String[] args) {
  
    Person person = new Person("Jim", "Knopf", 21);
    Person p2 = new Person("Jill", "Sanders", 20);
    // Jill gets married to Jim
    // and takes his name
    p2.setLastName("Knopf");
    System.out.println(p2);
  }
}

 

建立 Address 對象

Address.java:

package com.vogella.javastarter.exercises1;

public class Address {

  private String street;
  private String number;
  private String postalCode;
  private String city;
  private String country;
  
  public String getStreet() {
    return street;
  }
  
  public void setStreet(String street) {
    this.street = street;
  }
  
  public String getNumber() {
    return number;
  }
  
  public void setNumber(String number) {
    this.number = number;
  }
  
  public String getPostalCode() {
    return postalCode;
  }
  public void setPostalCode(String postalCode) {
    this.postalCode = postalCode;
  }
  
  public String getCity() {
    return city;
  }
  
  public void setCity(String city) {
    this.city = city;
  }
  
  public String getCountry() {
    return country;
  }
  
  public void setCountry(String country) {
    this.country = country;
  }
  
  public String toString() {
    return street + " " + number + " " + postalCode + " " + city + " "
        + country;
  }
}

Person.java:

package com.vogella.javastarter.exercises1;

class Person {

  String firstName;
  String lastName;
  int age;
  private Address address;
  
  public Person(String a, String b, int value) {
    firstName = a;
    lastName = b;
    age=value;
  }
  
  public String getFirstName() {
    return firstName;
  }
  
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  
  public String getLastName() {
    return lastName;
  }
  
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  
  public int getAge() {
    return age;
  }
  
  public void setAge(int age) {
    this.age = age;
  }
  
  public Address getAddress() {
    return address;
  }
  
  public void setAddress(Address address) {
    this.address = address;
  }
  
  @Override
  public String toString() {
    return firstName + " " + lastName;
  }
}

 

Main.java:

package com.vogella.javastarter.exercises1;

public class Main {

  public static void main(String[] args) {
  
    // I create a person
    Person pers = new Person("Jim", "Knopf", 31);
    // set the age of the person to 32
    pers.setAge(32);

    // just for testing I write this to the console
    System.out.println(pers);
    /*
     * actually System.out.println always calls toString, if you do not
     * specify it so you could also have written System.out.println(pers);
     */
    // create an address
    Address address = new Address();
    // set the values for the address
    address.setCity("Heidelberg");
    address.setCountry("Germany");
    address.setNumber("104");
    address.setPostalCode("69214");
    address.setStreet("Musterstr.");

    // assign the address to the person
    pers.setAddress(address);

    // dispose reference to address object
    address = null;

    // person is moving to the next house in the same street
    pers.getAddress().setNumber("105");

  }

}

 

基礎語句

if-then 和 if-then-else 語句

if-then 語句是控制語句,若是 if 部分表達式的結果爲 true 將執行其定義的代碼塊。當 if 部分表達式結果爲 false 則執行 else 代碼塊(如有的話)。

如下部分來自Java24_6th_ch7

下面的代碼演示了經過兩個方法演示了 if-then 以及 if-then-else 語句:

class Game {
    public static void main(String[] arguments) {
        int total = 0;
        int score = 7;
        if (score == 7) {
            System.out.println("You score a touchdown!");
        }
        if (score == 3) {
            System.out.println("You kick a field goal!");
        }
        total = total + score;
        System.out.println("Total score: " + total);
    }
}

Switch

switch 語句是一個多條件選擇執行語句簡稱開關語句,相似於 if-else語句。在 switch 的每個分支裏面都必須寫 breakbreak 表示退出整個 switch語句,若是不使用 break 語句則當第一個 case 匹配後,會順序執行後面的程序代碼,而無論後面的 case 是否匹配,直到遇到 break語句爲止,下面是 switch 語句的一個示例:

import java.util.*;

class Clock {
    public static void main(String[] arguments) {
        // get current time and date
        Calendar now = Calendar.getInstance();
        int hour = now.get(Calendar.HOUR_OF_DAY);
        int minute = now.get(Calendar.MINUTE);
        int month = now.get(Calendar.MONTH) + 1;
        int day = now.get(Calendar.DAY_OF_MONTH);
        int year = now.get(Calendar.YEAR);

        // display greeting
        if (hour < 12) {
            System.out.println("Good morning.\n");
        } else if (hour < 17) {
            System.out.println("Good afternoon.\n");
        } else {
            System.out.println("Good evening.\n");
        }

        // begin time message by showing the minutes
        System.out.print("It's");
        if (minute != 0) {
            System.out.print(" " + minute + " ");
            System.out.print( (minute != 1) ? "minutes" :
                "minute");
            System.out.print(" past");
        }

        // display the hour
        System.out.print(" ");
        System.out.print( (hour > 12) ? (hour - 12) : hour );
        System.out.print(" o'clock on ");

        // display the name of the month
        switch (month) {
            case 1:
                System.out.print("January");
                break;
            case 2:
                System.out.print("February");
                break;
            case 3:
                System.out.print("March");
                break;
            case 4:
                System.out.print("April");
                break;
            case 5:
                System.out.print("May");
                break;
            case 6:
                System.out.print("June");
                break;
            case 7:
                System.out.print("July");
                break;
            case 8:
                System.out.print("August");
                break;
            case 9:
                System.out.print("September");
                break;
            case 10:
                System.out.print("October");
                break;
            case 11:
                System.out.print("November");
                break;
            case 12:
                System.out.print("December");
        }

        // display the date and year
        System.out.println(" " + day + ", " + year + ".");
    }
}

 switch的後面能夠帶類型: character, an integer, or a string,後面要接break。 另外還有default。注意string在java7才支持。

public class Commodity {
    public static void main(String[] arguments) {
        String command = "BUY";
        int balance = 550;
        int quantity = 42;

        switch (command) {
            case "BUY":
               quantity += 5;
                balance -= 20;
                break;
            case "SELL":
                quantity -= 5;
                balance += 15;
        }
        System.out.println("Balance: " + balance + "\n"
            + "Quantity: " + quantity);
        }
}

布爾操做

使用 == 來比較兩個原始類型是否相同或者比較兩個引用類型是否指向同一個對象。使用 equals() 方法比較兩個不一樣的對象是否相等。

&& 和 || 都是短路方法,意思是一旦表達        式中某個條件判斷結果已經明確時,方法會中止再也不執行後面的條件判斷。好比:(true || ...) 結果始終是 true(false && ...) 結果始終是 false。使用示例:(var !=null     &&                     var.method1() ...)確保在調用 var.method1() 以前變量 var 始終不爲 null

表4

Operations Description
== 比較,對於原始類型比較兩個值,對於引用比較引用的對象地址
&&
!= 不等於
a.equals(b) 檢查字符串 a 是否等於字符串 b
a.equalsIgnoreCase(b) 檢查字符串 a 是否等於字符串 b,忽略大小寫
If (value ? false : true) {} 三元操做,若是 value == true 返回 true

 

循環語句

for 循環

循環處理的語句。Java的for語句形式有兩種:一種是和C語言中的for語句形式同樣,另外一種形式用於在集合和數組之中進行迭代。有時候把這種形式稱爲加強的 for(enhanced for) 語句,它可使循環更加緊湊和容易閱讀。它的通常形式爲 for(;;) 語句; 初始化老是一個賦值語句,它用來給循環控制變量賦初值;條件表達式是一個關係表達式,它決定何時退出循環;增量定義循環控制變量每循環一次後            按什麼方式變化。這三個部分之間用";"分開。例如:

for循環定義:

for(initialization; expression; update_statement)
{   //block of code to run 
}

示例語句:

public class ForTest {
  public static void main(String args[]) {
  for(int i = 1; i < 10; i = i+1) {
    System.out.println("value of i : " + i);
    }
  }
}

多個變量:

int i, j;
for (i = 0, j = 0; i * j < 1000; i++, j += 2) {
    System.out.println(i + 「 * 「 + j + 「 = 「 + (i * j));
}

初始化部分也能夠爲空。

for ( ; displayCount < endValue; displayCount++) {
    // loop statements would be here
}

 

While循環

while 循環語句是一個控制結構,能夠重複的特定任務次數。在執行時,若是布爾表達式的結果爲真,則循環中的動做將被執行,不然就跳出循環。

語法:

while(expression)
{  // block of code to run
}

示例:

public class WhileTest {

  public static void main(String args[]) {
  
    int x = 1;
    while (x < 10) {
      System.out.println("value of x : " + x);
      x++;
    }
  }
}

                

do-while 循環

do-while 循環與 while 循環很是相似,區別在於 while 循環先進行條件判斷再開始循環,do-while 循環則是先循環在進行條件判斷。

語法:

do{  
    // block of code to run
} while(expression);

示例:    

public class DoTest {
  public static void main(String args[]) {
    int x = 1;
    do {
      System.out.println("value of x : " + x);
      x++;
    } while (x < 10);
  }
}

 

循環命名適用於continue和break。
 

int points = 0;
int target = 100;
targetLoop:
while (target <= 100) {
    for (int i = 0; i < target; i++) {
        if (points > 50)
            break targetLoop;
        points = points + i;
    }
}

數組

數組是有序數據(同一類型數據)的集合,數組中的項稱爲元素,數組中的每一個元素使用相同的數組名和下標來惟一地肯定數組中的元素。數組中的第一個元素下標爲 0,第二個元素下標爲 1 ... 以此類推。

布爾類型在數組中默認值false,int默認值0,字符串 '\0',對象類型則默認爲null。
長度:.length。

public class TestMain {
    public static void main(String[] args) {
        
        // declares an array of integers
        int[] array;
        
        // allocates memory for 10 integers
        array = new int[10];
                    
        // initialize values
        array[0] = 10;
        // initialize second element
        array[1] = 20;
        array[2] = 30;
        array[3] = 40;
        array[4] = 50;
        array[5] = 60;
        array[6] = 70;
        array[7] = 80;
        array[8] = 90;
        array[9] = 100;    
    }
}

 

字符串也能夠當作數組處理:

class SpaceRemover {
    public static void main(String[] args) {
        String mostFamous = "Rudolph the Red-Nosed Reindeer";
        char[] mfl = mostFamous.toCharArray();
        for (int dex = 0; dex < mfl.length; dex++) {
            char current = mfl[dex];
            if (current != ' ') {
                System.out.print(current);
            } else {
                System.out.print('.');
            }
        }
        System.out.println();
    }
}

數組排序

import java.util.*;

class Name {
    public static void main(String[] args) {
        String names[] = { "Lauren", "Audrina", "Heidi", "Whitney",
            "Stephanie", "Spencer", "Lisa", "Brody", "Frankie",
            "Holly", "Jordan", "Brian", "Jason" };
        System.out.println("The original order:");
        for (int i = 0; i < names.length; i++) {
            System.out.print(i + ": " + names[i] + " ");
        }
        Arrays.sort(names);
        System.out.println("\nThe new order:");
        for (int i = 0; i < names.length; i++) {
            System.out.print(i + ": " + names[i] + " ");
        }
        System.out.println();
    }
}

注意:字符串和基礎類型只能升序。

下面統計單詞出現次數:

class Wheel {
    public static void main(String[] args) {
        String phrase[] = {
            "A STITCH IN TIME SAVES NINE",
            "DON'T EAT YELLOW SNOW",
            "JUST DO IT",
            "EVERY GOOD BOY DOES FINE",
            "I WANT MY MTV",
            "I LIKE IKE",
            "PLAY IT AGAIN, SAM",
            "FROSTY THE SNOWMAN",
            "ONE MORE FOR THE ROAD",
            "HOME FIELD ADVANTAGE",
            "VALENTINE'S DAY MASSACRE",
            "GROVER CLEVELAND OHIO",
            "SPAGHETTI WESTERN",
            "AQUA TEEN HUNGER FORCE",
            "IT'S A WONDERFUL LIFE"
        };
        int[] letterCount = new int[26];
        for (int count = 0; count < phrase.length; count++) {
            String current = phrase[count];
            char[] letters = current.toCharArray();
            for (int count2 = 0;  count2 < letters.length; count2++) {
                char lett = letters[count2];
                if ( (lett >= 'A') & (lett <= 'Z') ) {
                    letterCount[lett - 'A']++;
                }
            }
        }
        for (char count = 'A'; count <= 'Z'; count++) {
            System.out.print(count + ": " +
                letterCount[count - 'A'] +
                " ");
        }
        System.out.println();
    }
}

針對數組和容器加強的 for循環

可使用下面更簡單的 for 循環語句來遍歷數組以及容器類,語法爲:

for(declaration : expression)
{
  // body of code to be executed
}

用法示例:

    

public class TestMain {
    public static void main(String[] args) {
    
        // declares an array of integers
        int[] array;
    
        // allocates memory for 10 integers
        array = new int[10];
    
        // initialize values
        array[0] = 10;
        // initialize second element
        array[1] = 20;
        array[2] = 30;
        array[3] = 40;
        array[4] = 50;
        array[5] = 60;
        array[6] = 70;
        array[7] = 80;
        array[8] = 90;
        array[9] = 100;
    
        int idx = 0;
        for (int i : array) {
            System.out.println("Element at index " + idx + " :"  + i);
            idx++;
        }
    }
}

字符串

Java 中的字符串

Java 語言中使用 String 類來表示字符串,全部的字符串,如:"hello" 都是這個類的一個實例。字符串是不可變類型,好比:給String 對象賦新的值會建立一個新的 String 對    象。

Java 中的字符串池

Java 使用 String 池來提升字符串對象的內存使用效率。由於 Java 中字符串對象是不可變類型,所以字符串池容許重複使用已存在的字符串而不是每次都建立一個新的。

若是同一個字符串在 Java 代碼中被屢次使用,Java 虛擬機只會建立一個改字符串實例,並將其保存在字符串池中。

當一個 String 對象建立後,如:String s = "constant",字符串 "connstant" 會被保存在池中。不過,new 操做符會強制建立一個新的 String 對象拷貝,            併爲它分配新的內存,好比:String s = new String("constant");

在 Java 中比較字符串

在 Java 中須要使用 equals() 來比較字符串對象,好比:s1.equals(s2)。使用 == 來比較字符串對象是不正確的,由於 == 是用來比較對象引用是否相同。因爲 Java 使用字符串池,所以 == 在某些時候會給出正確的結果。

下面的例子將會獲得正確的結果:

String a = "Hello";
String b = "Hello";
if (a==b) {
  // if statement is true
  // because String pool is used and
  // a and b point to the same constant
}

下面的比較會返回 false:          

String a = "Hello";
String b = new String("Hello");
if (a==b) {
  
} else {
                  // if statement is false
  // because String pool is used and 
  // a and b point to the same constant
}

警告:當進行字符串比較時,應該老是使用 equals() 方法。等於判斷:favorite.equals(guess)。

長度計算:

String cinematographer = 「Stuart Dryburgh」;
int nameLength = cinematographer.length();

字符串鏈接時,有一方是字符串,另外一方能夠轉爲字符串,這點比python要爽。
 

使用字符串


String是對象,首字母大寫。
println()比print()多了換行

轉義字符
\’ Single quotation mark
\」 Double quotation mark
\\ Backslash
\t Tab
\b Backspace
\r Carriage return
\f Formfeed
\n Newline

下面的表格列出了經常使用的字符串方法

表格5:

Command Description
"Testing".equals(text1); 字符串對象 text1 的值等於 "Testing" 時返回 true
"Testing".equalsIgnoreCase(text1); 字符串對象 text1 的值等於 "Testing" 時返回 true。忽略大小寫
StringBuffer str1 = new StringBuffer(); 聲明並實例化一個 StringBuffer 對象
str.charat(1); 返回字符串中位置 1 的字符
str.substring(1); 刪除第一個字符,隻影響輸出結果
str.substring(1, 5); 返回第2個至第5個字符
str.indexOf("Test") 在字符串中查找 "Test" 並返回位置
str.lastIndexOf("ing") 從後向前在字符串中查找 "ing" 並返回位置
str.endsWith("ing") 檢查字符串是否以 "ing" 結尾                                                          
str.startsWith("Test") 檢查字符串是否以 "Test" 開頭
str.trim() 刪除字符串先後的空格
str.replace(str1, str2) 將字符串中的 "str1" 替換爲 "str2"
str2.concat(str1); 將 "str1" 拼接到 "str2" 尾部
str.toLowerCase()/str.toUpperCase() 轉換字符串爲小寫或大寫
str1 + str2 鏈接字符串

String[] array = myString.split("-");

String[] array2 = myString.split("\\.");

將字符串根據 "-" 分隔成字符串數組。注意分割內容部分是正則表達式。                       

 toUpperCase()  toLowerCase() 不會改變原字符串。indexOf() 找不到返回-1,不然返回索引。

class Credits {
    public static void main(String[] args) {
        // set up film information
        String title = "The Piano";
        int year = 1993;
        String director = "Jane Campion";
        String role1 = "Ada";
        String actor1 = "Holly Hunter";
        String role2 = "Baines";
        String actor2 = "Harvey Keitel";
        String role3 = "Stewart";
        String actor3 = "Sam Neill";
        String role4 = "Flora";
        String actor4 = "Anna Paquin";
        // display information
        System.out.println(title + " (" + year + ")\n" +
            "A " + director + " film.\n\n" +
            role1 + "\t" + actor1 + "\n" +
            role2 + "\t" + actor2 + "\n" +
            role3 + "\t" + actor3 + "\n" +
            role4 + "\t" + actor4);
    }
}

 

Lambda 表達式    

什麼是 lambda 表達式

Java 編程語言從 Java 8 開始支持 lambda 表達式。Lambda 表達式是能夠做爲參數使用的一段代碼。lambda 表達式容許指定的代碼在稍後執行。Lambda 表達式    用於任何函數式接口適用的地方。

lambda 表達式和閉包的區別

lambda 表達式是一個匿名函數,好比:它能夠做爲參數定義。閉包是一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。這意味着閉包能夠訪問不在他參數列表中的變量,而且能夠將閉包賦值給一個變量。

Java 支持 lambda 表達式,但不支持閉包。

引入 lambda 表達式的目的

使用 lambda 表達式比其餘 Java 語法結構更加簡潔,好比,Java 8 中 Collections 新增了一個 forEach 方法,這個方法能夠接受 lambda 表達式,以下例:

List<String> list = new ArrayList<>();
list.add("vogella.com");
list.add("google.com");
list.add("heise.de");
list.forEach(System.out::println);

使用方法引用

在 lambda 表達式中可使用方法引用,方法引用定義能夠經過 CalledFrom::method 來調用的方法,CallFrom 能夠是:

  • instance::instanceMethod

  • SomeClass::staticMethod

  • SomeClass::instanceMethod

好比下面代碼:

List<String> list = new ArrayList<>();
list.add("vogella.com");
list.add("google.com");
list.add("heise.de");
list.forEach(s-> System.out.println(s));

流(stream)

Java 8 中的流(stream)是什麼?

流(stream)是支持串行和並行聚合操做的元素序列。

新增長的Stream API (java.util.stream)引入了在Java裏能夠工做的函數式編程。這是目前爲止對java庫最大的一次功能添加,但願程序員經過編寫有效、整潔和簡明的代碼,可以大大提升生產率。    

IntStream

用來建立支持串行和並行聚合操做的包含原始 int 類型的元素序列。下面演示的range和python的range很相似。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class IntStreamExample {
            
  public static void main(String[] args) {
  
    // printout the numbers from 1 to 100
    IntStream.range(1, 101).forEach(s -> System.out.println(s));
    
    // create a list of integers for 1 to 100
    List<Integer> list = new ArrayList<>();
    IntStream.range(1, 101).forEach(it -> list.add(it));
    System.out.println("Size " + list.size());
  }
}

 stream 和 lambda 的 Reduction 操做

Reduction 操做接受一個元素序列爲輸入,反覆使用某個合併操做,把序列中的元素合併成一個彙總的結果,參考下面代碼:

Task.java: 

public class Task {
    
      private String summary;
      private int duration;
      
      public Task(String summary, int duration) {
        this.summary = summary;
        this.duration = duration;
      }
      public String getSummary() {
        return summary;
      }
      public void setSummary(String summary) {
        this.summary = summary;
      }
      public int getDuration() {
        return duration;
      }
      public void setDuration(int duration) {
        this.duration = duration;
      }
      
}

 

StreamTester.java:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class StreamTester {
      public static void main(String[] args) {
      
            Random random = new Random();
            // Generate a list of random task
            List<Task> values = new ArrayList<>();
            IntStream.range(1, 20).forEach(i -> values.add(new Task("Task" + random.nextInt(10), random.nextInt(10))));
    
            
            // get a list of the distinct task summary field
            List<String> resultList = 
                  values.stream().filter(t -> t.getDuration() > 5).map(t -> t.getSummary()).distinct().collect(Collectors.toList());
            System.out.println(resultList);
            
            
            // get a concatenated string of Task with a duration longer than 5 hours
            String collect = 
                values.stream().filter(t -> t.getDuration() > 5).map(t -> t.getSummary()).distinct().collect(Collectors.joining("-"));
            System.out.println(collect);
      }
}

Optional    

若是你調用未初始化的字段或方法會收到    NullPointerException異常(NPE)。java.util.Optional類用於避免這些NPE。它經過方法的簽名直接看到值是否存在,而不是經過javadoc返回null,它的 filter方法在沒有值時返回空對象。該功能至關於把python默認值的一小部分學了過來,可是操做要複雜得多。

建立:

   

// use this if the object is not null
opt = Optional.of(o);
// creates an empty Optional, if o is null
opt = Optional.ofNullable(o);
// create an empty Optional
opt = Optional.empty();

ifPresent能夠查看對象是否存在。          

Todo todo = new Todo(-1);
Optional<Todo> optTodo = Optional.of(todo);
// get the id of the todo or a default value 
optTodo.ifPresent(t-> System.out.println(t.getId()));

   

Todo todo = new Todo(-1);    
    Optional<Todo> optTodo = Optional.of(todo);
    // get the summary (trimmed) of todo if the id is higher than 0
    Optional<String> map = optTodo.filter(o -> o.getId() > 0).map(o -> o.getSummary().trim());  
    // same as above but print it out
    optTodo.filter(o -> o.getId() > 0).map(o -> o.getSummary().trim()).ifPresent(System.out::println);
// using a String
String s = "Hello";
Optional<String> maybeS = Optional.of(s);
// get length of the String or -1 as default
int len = maybeS.map(String::length).orElse(-1);
// orElseGet allows to construct an object / value with a Supplier
int calStringlen = maybeS.map(String::length).orElseGet(()-> "Hello".length());

實例:

import java.util.Optional;

public class Java8Tester {

   public static void main(String args[]){
   
      Java8Tester java8Tester = new Java8Tester();
      Integer value1 = null;
      Integer value2 = new Integer(10);
        
      //Optional.ofNullable - allows passed parameter to be null.
      Optional<Integer> a = Optional.ofNullable(value1);
        
      //Optional.of - throws NullPointerException if passed parameter is null
      Optional<Integer> b = Optional.of(value2);
      System.out.println(java8Tester.sum(a,b));
   }
    
   public Integer sum(Optional<Integer> a, Optional<Integer> b){
    
      //Optional.isPresent - checks the value is present or not
        
      System.out.println("First parameter is present: " + a.isPresent());
      System.out.println("Second parameter is present: " + b.isPresent());
        
      //Optional.orElse - returns the value if present otherwise returns
      //the default value passed.
      Integer value1 = a.orElse(new Integer(0));
        
      //Optional.get - gets the value, value should be present
      Integer value2 = b.get();
      return value1 + value2;
   }
}

類型轉換(casting)

若是使用不一樣類型的變量,Java 須要進行顯式類型轉換,下面章節是一些例子。

轉換爲字符串

參考下面的代碼將其餘類型對象轉換爲字符串:            

// Convert from int to String
String s1 = String.valueOf (10); // "10" 
// Convert from double to String
String s2 = String.valueOf (Math.PI); // "3.141592653589793"
// Convert from boolean to String
String s3 = String.valueOf (1 < 2); // "true" 
// Convert from date to String
String s4 = String.valueOf (new Date()); // "Tue Jun 03 14:40:38 CEST 2003"

    

22.2 將字符串轉換爲數字

// Conversion from String to int
int i = Integer.parseInt(String);
// Conversion from float to int
float f = Float.parseFloat(String);
// Conversion from double to int
double d = Double.parseDouble(String);

從字符串到數字的轉換獨立於區域設置,好比:它老是使用數字的英語表示方法。在這種表示法中 "8.20" 是一個正確的數字,但德國藏用的 "8,20" 則是一個錯誤的數字。                

要轉換相似於德國的數字表示,你須要使用 NumberFormat 類。咱們面臨的挑戰是,當相似於 "98.00" 這類數字表示時, NumberFormat 會將其轉換成 Long 而不是 Double。若是須要轉換成 Double 請參考下面的方法,

private Double convertStringToDouble(String s) {

    Locale l = new Locale("de", "DE");
    Locale.setDefault(l);
    NumberFormat nf = NumberFormat.getInstance();
    Double result = 0.0;
    
    try {
      if (Class.forName("java.lang.Long").isInstance(nf.parse(s))) {
        result = Double.parseDouble(String.valueOf(nf.parse(s)));
      } else {
        result = (Double) nf.parse(new String(s));
      }
    } catch (ClassNotFoundException e1) {
      e1.printStackTrace();
    } catch (ParseException e1) {
      e1.printStackTrace();
    }         
    return result;
  }

 

22.3 Double 轉換爲 int

int i = (int) double;

22.4 SQL 日期類型轉換

使用下面的類將 Date 類型轉換爲 SQL 的 Date類型

package test;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
    
public class ConvertDateToSQLDate {

    private void convertDateToSQL(){
       SimpleDateFormat template = 
          new SimpleDateFormat("yyyy-MM-dd"); 
          java.util.Date enddate = new java.util.Date("10/31/99"); 
          java.sql.Date sqlDate = java.sql.Date.valueOf(template.format(enddate)); 
       
    }
      public static void main(String[] args) {
        ConvertDateToSQLDate date = new ConvertDateToSQLDate();
        date.convertDateToSQL();
      }   
}

boolean ( Boolean class),  byte ( Byte ),  char ( Character ),  double ( Double ),
float ( Float ),  int ( Integer ),  long ( Long )和short ( Short )能自動裝箱(Autoboxing)和自動拆箱(Unboxing)。

 下面代碼在1.5之後不會報錯。

Float total = new Float(1.3F);
float sum = total / 5;

計劃任務

Java 支持計劃任務,計劃任務能夠被執行一次或屢次。

使用 java.util.Timer 和 java.util.TimerTask 來完成計劃任務。實現 TimeTask 的對象將會由 Time 在指定的時間間隔執行。

MyTask.java:

package schedule;
import java.util.TimerTask;

public class MyTask extends TimerTask {

  private final String string;
  private int count = 0;
  
  public MyTask(String string) {
    this.string = string;
  }
  @Override
  public void run() {
    count++;
    System.out.println(string + " called " + count);
  }
}

 

ScheduleTest.java:

package schedule;
import java.util.Timer;
public class ScheduleTest {
  public static void main(String[] args) {
    Timer timer = new Timer();
    // wait 2 seconds (2000 milli-secs) and then start
    timer.schedule(new MyTask("Task1"), 2000);
    for (int i = 0; i < 100; i++) {
      // wait 1 seconds and then again every 5 seconds
      timer.schedule(new MyTask("Task " + i), 1000, 5000);
    }
  }
}

 提示:開源框架 "quartz" 提供了加強的計劃任務功能。參考: http://www.onjava.com/lpt/a/4637 或 http://www.quartz-scheduler.org/

 

正則表達式

通配符

Regular Expression Description
. Matches any character
^regex Finds regex that must match at the beginning of the line.
regex$ Finds regex that must match at the end of the line.
[abc] Set definition, can match the letter a or b or c.
[abc][vz] Set definition, can match a or b or c followed by either v or z.
[^abc] When a caret appears as the first character inside square brackets, it negates the pattern. This pattern matches any character except a or b or c.
[a-d1-7] Ranges: matches a letter between a and d and figures from 1 to 7, but not d1.
X|Z Finds X or Z.
XZ Finds X directly followed by Z.
$ Checks if a line end follows.

元字符

Regular Expression Description
\d Any digit, short for [0-9]
\D A non-digit, short for [^0-9]
\s A whitespace character, short for [ \t\n\x0b\r\f]
\S A non-whitespace character, short for [^\s]
\w A word character, short for [a-zA-Z_0-9]
\W A non-word character [^\w]
\S+ Several non-whitespace characters
\b Matches a word boundary where a word character is [a-zA-Z0-9_].

These meta characters have the same first letter as their representation, e.g., digit, space, word, and boundary. Uppercase symbols define the opposite.

數量

Regular Expression Description Examples
* Occurs zero or more times, is short for {0,} X* finds no or several letter X, 
.* finds any character sequence
+ Occurs one or more times, is short for {1,} X+ - Finds one or several letter X
? Occurs no or one times, ? is short for {0,1}. X? finds no or exactly one letter X
{X} Occurs X number of times, {} describes the order of the preceding liberal \d{3} searches for three digits, .{10}for any character sequence of length 10.
{X,Y} Occurs between X and Y times, \d{1,4} means \d must occur at least once and at a maximum of four.
*? ? after a quantifier makes it a reluctant quantifier. It tries to find the smallest match. This makes the regular expression stop at the first match.  

 

參考資料

英文地址:http://www.vogella.com/tutorials/JavaIntroduction/article.html

http://codex.wiki/post/165971-434

最佳實踐的代碼:http://javaboutique.internet.com/

 

微博 http://weibo.com/cizhenshi 做者博客:http://my.oschina.net/u/1433482 python測試開發精華羣 291184506 PythonJava單元白盒測試 144081101

 

其餘內容

參數處理

class BlankFiller {
    public static void main(String[] arguments) {
        System.out.println("The " + arguments[0]
            + " " + arguments[1] + " fox "
            + "jumped over the "
            + arguments[2] + " dog."
        );
    }
}

命令行執行:

# java BlankFiller hello new world
The hello new fox jumped over the world dog.

在NetBeans執行:
Run -> Project Configuration -> Customize, 輸入BlankFiller,參數部分輸入hello new world。
按F6或者Run -> run project。

Applet實例

JApplet的行爲和屬性:
equals()
setBackground()
add()
setLayout()

import javax.swing.*;

public class SalutonFrame extends JFrame {
    public SalutonFrame() {
        super("Saluton mondo!");
        setLookAndFeel();
        setSize(350, 100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        SalutonFrame sal = new SalutonFrame();
    }
}

上面的

super("Saluton mondo!");

設置了標題,也能夠單獨用方法設置:setTitle(「Main Frame」);

設置大小的另一種方法是先填充,而後使用pack()。同時,默認會有合適的大小。

 setDefaultCloseOperation()的選項:JFrame.EXIT_ON_CLOSE、Frame.DISPOSE_ON_CLOSE、JFrame.DO_NOTHING_ON_CLOSE、JFrame.HIDE_ON_CLOSE。

java7引入的加強視覺方案引入方法:

UIManager.setLookAndFeel(
「com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel」
);

上述實例的效果以下:

下面實例增長button:

import javax.swing.*;
import java.awt.*;

public class Playback extends JFrame {
    public Playback() {
        super("Playback");
        setLookAndFeel();
        setSize(225, 80);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        FlowLayout flo = new FlowLayout();
        setLayout(flo);
        JButton play = new JButton("Play");
        JButton stop = new JButton("Stop");
        JButton pause = new JButton("Pause");
        add(play);
        add(stop);
        add(pause);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        Playback pb = new Playback();
    }
}

效果以下:

CheckBoxes.java

import javax.swing.*;
import java.awt.*;

public class CheckBoxes extends JFrame {
    public CheckBoxes() {
        super("CheckBoxes");
        setLookAndFeel();
        setSize(195, 170);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JCheckBox jumboSize = new JCheckBox("Jumbo Size", true);
        JCheckBox frogLegs = new JCheckBox("Frog Leg Grande", true);
        JCheckBox fishTacos = new JCheckBox("Fish Taco Platter", false);
        JCheckBox emuNuggets = new JCheckBox("Emu Nuggets", false);
        FlowLayout flo = new FlowLayout();
        ButtonGroup meals = new ButtonGroup();
        meals.add(frogLegs);
        meals.add(fishTacos);
        meals.add(emuNuggets);
        setLayout(flo);
        add(jumboSize);
        add(frogLegs);
        add(fishTacos);
        add(emuNuggets);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        CheckBoxes cb = new CheckBoxes();
    }
}

執行效果:

ClockPanel.java

import javax.swing.*;
import java.awt.*;
import java.util.*;

public class ClockPanel extends JPanel {
    public ClockPanel() {
        super();
        String currentTime = getTime();
        JLabel time = new JLabel("Time: ");
        JLabel current = new JLabel(currentTime);
        add(time);
        add(current);
    }

    final String getTime() {
        String time;
        // get current time and date
        Calendar now = Calendar.getInstance();
        int hour = now.get(Calendar.HOUR_OF_DAY);
        int minute = now.get(Calendar.MINUTE);
        int month = now.get(Calendar.MONTH) + 1;
        int day = now.get(Calendar.DAY_OF_MONTH);
        int year = now.get(Calendar.YEAR);

        String monthName = "";
        switch (month) {
            case (1):
                monthName = "January";
                break;
            case (2):
                monthName = "February";
                break;
            case (3):
                monthName = "March";
                break;
            case (4):
                monthName = "April";
                break;
            case (5):
                monthName = "May";
                break;
            case (6):
                monthName = "June";
                break;
            case (7):
                monthName = "July";
                break;
            case (8):
                monthName = "August";
                break;
            case (9):
                monthName = "September";
                break;
            case (10):
                monthName = "October";
                break;
            case (11):
                monthName = "November";
                break;
            case (12):
                monthName = "December";
        }
        time = monthName + " " + day + ", " + year + " "
            + hour + ":" + minute;
        return time;
    }
}

ClockFrame.java

import java.awt.*;
import javax.swing.*;

public class ClockFrame extends JFrame {
    public ClockFrame() {
        super("Clock");
        setLookAndFeel();
        setSize(225, 125);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        FlowLayout flo = new FlowLayout();
        setLayout(flo);
        ClockPanel time = new ClockPanel();
        add(time);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        ClockFrame clock = new ClockFrame();
    }
}

執行效果

ComboBoxes.java 

import javax.swing.*;
import java.awt.*;

public class ComboBoxes extends JFrame {
    public ComboBoxes() {
        super("ComboBoxes");
        setLookAndFeel();
        setSize(345, 120);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JComboBox profession = new JComboBox();
        FlowLayout flo = new FlowLayout();
        profession.addItem("Butcher");
        profession.addItem("Baker");
        profession.addItem("Candlestick maker");
        profession.addItem("Fletcher");
        profession.addItem("Fighter");
        profession.addItem("Technical writer");
        setLayout(flo);
        add(profession);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        ComboBoxes cb = new ComboBoxes();
    }
}

執行效果:

TextArea.java

import javax.swing.*;
import java.awt.*;

public class TextArea extends JFrame {
    public TextArea() {
        super("TextArea");
        setLookAndFeel();
        setSize(500, 190);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTextArea comments = new JTextArea(8, 40);
        FlowLayout flo = new FlowLayout();
        setLayout(flo);
        add(comments);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        TextArea ta = new TextArea();
    }
}

執行效果:

TextField.java

import javax.swing.*;
import java.awt.*;

public class TextField extends JFrame {
    public TextField() {
        super("TextField");
        setLookAndFeel();
        setSize(375, 80);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JLabel pageLabel = new JLabel("Web page address: ", JLabel.RIGHT);
        JTextField pageAddress = new JTextField(20);
        FlowLayout flo = new FlowLayout();
        setLayout(flo);
        add(pageLabel);
        add(pageAddress);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        TextField tf = new TextField();
    }
}

執行效果:

TwoFrames.java

import javax.swing.*;

public class TwoFrames extends JFrame {
    public TwoFrames() {
        super("First Frame");
        setSize(350, 100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLookAndFeel();
        SecondFrame two = new SecondFrame();
        setVisible(true);
        two.setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        TwoFrames tf = new TwoFrames();
    }
}

class SecondFrame extends JFrame {
    SecondFrame() {
        super("Second Frame");
        setSize(150, 80);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

 

import java.awt.*;

public class RootApplet extends javax.swing.JApplet {
    int number;

    public void init() {
        number = 225;
    }

    public void paint(Graphics screen) {
       Graphics2D screen2D = (Graphics2D) screen;
       screen2D.drawString("The square root of " +
           number +
           " is " +
           Math.sqrt(number), 5, 50);
    }
}

執行效果:

 

基於FlowLayout的佈局:

import java.awt.*;
import javax.swing.*;

public class Crisis extends JFrame {
    JButton panicButton;
    JButton dontPanicButton;
    JButton blameButton;
    JButton mediaButton;
    JButton saveButton;

    public Crisis() {
        super("Crisis");
        setLookAndFeel();
        setSize(348, 128);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        FlowLayout flo = new FlowLayout();
        setLayout(flo);
        panicButton = new JButton("Panic");
        dontPanicButton = new JButton("Don't Panic");
        blameButton = new JButton("Blame Others");
        mediaButton = new JButton("Notify the Media");
        saveButton = new JButton("Save Yourself");
        add(panicButton);
        add(dontPanicButton);
        add(blameButton);
        add(mediaButton);
        add(saveButton);
        setVisible(true);
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        Crisis cr = new Crisis();
    }
}

執行效果:

 

另外還有GridLayout、

GridLayout grid = new GridLayout(2, 3);
setLayout(grid);

BorderLayout:

BorderLayout crisisLayout = new BorderLayout();
setLayout(crisisLayout);
add(panicButton, BorderLayout.NORTH);
add(dontPanicButton, BorderLayout.SOUTH);
add(blameButton, BorderLayout.EAST);
add(mediaButton, BorderLayout.WEST);
add(saveButton, BorderLayout.CENTER);

BoxLayout(垂直佈局):

JPanel pane = new JPanel();
BoxLayout box = new BoxLayout(pane, BoxLayout.Y_AXIS);
pane.setLayout(box);
pane.add(panicButton);
pane.add(dontPanicButton);
pane.add(blameButton);
pane.add(mediaButton);
pane.add(saveButton);
add(pane);

還能夠指定位置插入:

Insets around = new Insets(10, 6, 10, 3);

佈局實例:

import java.awt.*;
import javax.swing.*;

public class LottoMadness extends JFrame {

    // set up row 1
    JPanel row1 = new JPanel();
    ButtonGroup option = new ButtonGroup();
    JCheckBox quickpick = new JCheckBox("Quick Pick", false);
    JCheckBox personal = new JCheckBox("Personal", true);
    // set up row 2
    JPanel row2 = new JPanel();
    JLabel numbersLabel = new JLabel("Your picks: ", JLabel.RIGHT);
    JTextField[] numbers = new JTextField[6];
    JLabel winnersLabel = new JLabel("Winners: ", JLabel.RIGHT);
    JTextField[] winners = new JTextField[6];
    // set up row 3
    JPanel row3 = new JPanel();
    JButton stop = new JButton("Stop");
    JButton play = new JButton("Play");
    JButton reset = new JButton("Reset");
    // set up row 4
    JPanel row4 = new JPanel();
    JLabel got3Label = new JLabel("3 of 6: ", JLabel.RIGHT);
    JTextField got3 = new JTextField("0");
    JLabel got4Label = new JLabel("4 of 6: ", JLabel.RIGHT);
    JTextField got4 = new JTextField("0");
    JLabel got5Label = new JLabel("5 of 6: ", JLabel.RIGHT);
    JTextField got5 = new JTextField("0");
    JLabel got6Label = new JLabel("6 of 6: ", JLabel.RIGHT);
    JTextField got6 = new JTextField("0", 10);
    JLabel drawingsLabel = new JLabel("Drawings: ", JLabel.RIGHT);
    JTextField drawings = new JTextField("0");
    JLabel yearsLabel = new JLabel("Years: ", JLabel.RIGHT);
    JTextField years = new JTextField();

    public LottoMadness() {
        super("Lotto Madness");
        setLookAndFeel();
        setSize(550, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridLayout layout = new GridLayout(5, 1, 10, 10);
        setLayout(layout);

        FlowLayout layout1 = new FlowLayout(FlowLayout.CENTER,
            10, 10);
        option.add(quickpick);
        option.add(personal);
        row1.setLayout(layout1);
        row1.add(quickpick);
        row1.add(personal);
        add(row1);

        GridLayout layout2 = new GridLayout(2, 7, 10, 10);
        row2.setLayout(layout2);
        row2.add(numbersLabel);
        for (int i = 0; i < 6; i++) {
            numbers[i] = new JTextField();
            row2.add(numbers[i]);
        }
        row2.add(winnersLabel);
        for (int i = 0; i < 6; i++) {
            winners[i] = new JTextField();
            winners[i].setEditable(false);
            row2.add(winners[i]);
        }
        add(row2);

        FlowLayout layout3 = new FlowLayout(FlowLayout.CENTER,
            10, 10);
        row3.setLayout(layout3);
        stop.setEnabled(false);
        row3.add(stop);
        row3.add(play);
        row3.add(reset);
        add(row3);

        GridLayout layout4 = new GridLayout(2, 3, 20, 10);
        row4.setLayout(layout4);
        row4.add(got3Label);
        got3.setEditable(false);
        row4.add(got3);
        row4.add(got4Label);
        got4.setEditable(false);
        row4.add(got4);
        row4.add(got5Label);
        got5.setEditable(false);
        row4.add(got5);
        row4.add(got6Label);
        got6.setEditable(false);
        row4.add(got6);
        row4.add(drawingsLabel);
        drawings.setEditable(false);
        row4.add(drawings);
        row4.add(yearsLabel);
        years.setEditable(false);
        row4.add(years);
        add(row4);
        
        setVisible(true);
    }
    
    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        LottoMadness frame = new LottoMadness();
    }
}

效果以下:

組件的開啓與關閉:

JButton previousButton = new JButton(「Previous」);
JButton nextButton = new JButton(「Next」);
JButton previousButton = new JButton(「Previous」);
JButton nextButton = new JButton(「Next」);

滾動條的構建

 

JSlider() 默認值50,範圍0-100

JSlider(int, int)

JSlider(int, int, int) 最小、最大和默認值。

 

方向: JSlider.VERTICAL or  JSlider.HORIZONTAL

好比:

JSlider guess = new JSlider(JSlider.VERTICAL, 1, 1000, 500);

 

其餘設置:

  setMajorTickSpacing(int)

  setMinorTickSpacing(int)

  

以下方式開啓:

setPaintTicks(boolean)或setPaintLabels(boolean)。

ChangeListener接口能夠改變事件:

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;

public class ColorSliders extends JFrame implements ChangeListener {
    ColorPanel canvas;
    JSlider red;
    JSlider green;
    JSlider blue;

    public ColorSliders() {
        super("Color Slide");
        setLookAndFeel();
        setSize(270, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);

        canvas = new ColorPanel();
        red = new JSlider(0, 255, 255);
        green = new JSlider(0, 255, 0);
        blue = new JSlider(0, 255, 0);

        red.setMajorTickSpacing(50);
        red.setMinorTickSpacing(10);
        red.setPaintTicks(true);
        red.setPaintLabels(true);
        red.addChangeListener(this);

        green.setMajorTickSpacing(50);
        green.setMinorTickSpacing(10);
        green.setPaintTicks(true);
        green.setPaintLabels(true);
        green.addChangeListener(this);

        blue.setMajorTickSpacing(50);
        blue.setMinorTickSpacing(10);
        blue.setPaintTicks(true);
        blue.setPaintLabels(true);
        blue.addChangeListener(this);

        JLabel redLabel = new JLabel("Red: ");
        JLabel greenLabel = new JLabel("Green: ");
        JLabel blueLabel = new JLabel("Blue: ");
        GridLayout grid = new GridLayout(4, 1);
        FlowLayout right = new FlowLayout(FlowLayout.RIGHT);
        setLayout(grid);
        
        JPanel redPanel = new JPanel();
        redPanel.setLayout(right);
        redPanel.add(redLabel);
        redPanel.add(red);
        add(redPanel);
        
        JPanel greenPanel = new JPanel();
        greenPanel.setLayout(right);
        greenPanel.add(greenLabel);
        greenPanel.add(green);
        add(greenPanel);
        
        JPanel bluePanel = new JPanel();
        bluePanel.setLayout(right);
        bluePanel.add(blueLabel);
        bluePanel.add(blue);
        add(bluePanel);
        add(canvas);
        
        setVisible(true);
    }

    public void stateChanged(ChangeEvent event) {
        JSlider source = (JSlider) event.getSource();
        if (source.getValueIsAdjusting() != true) {
            Color current = new Color(red.getValue(), green.getValue(),
                blue.getValue());
            canvas.changeColor(current);
            canvas.repaint();
        }
    }

    public Insets getInsets() {
        Insets border = new Insets(45, 10, 10, 10);
        return border;
    }
    
    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        ColorSliders cs = new ColorSliders();
    }
}

class ColorPanel extends JPanel {
    Color background;

    ColorPanel() {
        background = Color.red;
    }

    public void paintComponent(Graphics comp) {
        Graphics2D comp2D = (Graphics2D) comp;
        comp2D.setColor(background);
        comp2D.fillRect(0, 0, getSize().width, getSize().height);
    }

    void changeColor(Color newBackground) {
        background = newBackground;
    }
}

圖片的建立

 

ImageIcon stopSign = new ImageIcon(「stopsign.gif」);

ImageIcon saveFile = new ImageIcon(「images/savefile.gif」);

 

使用

ImageIcon siteLogo = new ImageIcon(「siteLogo.gif」);

JLabel logoLabel = new JLabel(siteLogo);

ImageIcon searchWeb = new ImageIcon(「searchGraphic.gif」);

JButton search = new JTextField(searchWeb);

 

JButton refresh = new JButton(「Refresh」, 「images/refreshIcon.gif」);

 

JToolBar()建立水平工具條

JToolBar(int),能夠是水平(SwingConstants.HORIZONTAL)或者垂直(SwingConstants.HORIZONTAL)。

容器:BorderLayout

BorderLayout border = new BorderLayout();

pane.setLayout(border);

JToolBar bar = new JToolBar(SwingConstants.VERTICAL);

ImageIcon play = new ImageIcon(「play.gif」);

JButton playButton = new JButton(play);

ImageIcon stop = new ImageIcon(「stop.gif」);

JButton stopButton = new JButton(stop);

ImageIcon pause = new ImageIcon(「pause.gif」);

JButton pauseButton = new JButton(pause);

bar.add(playButton);

bar.add(stopButton);

bar.add(pauseButton);

add(bar, BorderLayout.WEST);

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Tool extends JFrame {
    public Tool() {
        super("Tool");
        setLookAndFeel();
        setSize(370, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // build toolbar buttons
        ImageIcon image1 = new ImageIcon("d:\\newfile.gif");
        JButton button1 = new JButton(image1);
        ImageIcon image2 = new ImageIcon("d:\\openfile.gif");
        JButton button2 = new JButton(image2);
        ImageIcon image3 = new ImageIcon("d:\\savefile.gif");
        JButton button3 = new JButton(image3);

        // build toolbar
        JToolBar bar = new JToolBar();
        bar.add(button1);
        bar.add(button2);
        bar.add(button3);

        // build text area
        JTextArea edit = new JTextArea(8, 40);
        JScrollPane scroll = new JScrollPane(edit);

        // create frame
        BorderLayout border = new BorderLayout();
        setLayout(border);
        add("North", bar);
        add("Center", scroll);
        setVisible(true);
    }

     private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }

    public static void main(String[] arguments) {
        Tool frame = new Tool();
    }
}

 

簡單的applet實例:

import java.awt.*;
 
public class RootApplet extends javax.swing.JApplet {
    int number;
 
    public void init() {
        number = 225;
    }
 
    public void paint(Graphics screen) {
       Graphics2D screen2D = (Graphics2D) screen;
       screen2D.drawString("The square root of " +
           number +
           " is " +
           Math.sqrt(number), 5, 50);
    }
}

嵌入瀏覽器:

mport java.awt.*;

public class SalutonApplet extends javax.swing.JApplet {
    String greeting;

    public void init() {
        greeting = "Saluton mondo!";
    }

    public void paint(Graphics screen) {
        Graphics2D screen2D = (Graphics2D) screen;
        screen2D.drawString(greeting, 25, 50);
    }
}
<html>
<head>
<title>Saluton Mondo!</title>
</head>
<body bgcolor="#000000" text="#FF00FF">
<p>This is a Java applet.</p>
<applet
    code="SalutonApplet.class"
    codebase="..\\..\\build\\classes"
    height="150"
    width="300"
>
<p>You need a Java-enabled browser to see this.</p>
</applet>
</body>
</html>

參數傳遞:

import java.awt.*;

public class WeightScale extends javax.swing.JApplet {
    float lbs = 0F;
    float ozs;
    float kgs;
    float metricTons;
    String name = "somebody";

    public void init() {
        String lbsValue = getParameter("weight");
        if (lbsValue != null) {
            lbs = Float.valueOf(lbsValue);
        }
        String personValue = getParameter("person");
        if (personValue != null) {
            name = personValue;
        }
        ozs = (float) (lbs * 16);
        kgs = (float) (lbs / 2.204623);
        metricTons = (float) (lbs / 2204.623);
    }

    public void paint(Graphics screen) {
        Graphics2D screen2D = (Graphics2D) screen;
        screen2D.drawString("Studying the weight of " + name, 5, 30);
        screen2D.drawString("In pounds: " + lbs, 55, 50);
        screen2D.drawString("In ounces: " + ozs, 55, 70);
        screen2D.drawString("In kilograms: " + kgs, 55, 90);
        screen2D.drawString("In metric tons: " + metricTons, 55, 110);
    }
}

相應的HTML:

WeightScale.html

<applet code="WeightScale.class" codebase="..\\..\\build\\classes"
    height="170" width="210">
    <param name="person" value="Konishiki">
    <param name="weight" value="605">
</applet>

HTML5 要改用object標籤

<applet code="WeightScale.class" codebase="..\\..\\build\\classes"
    height="170" width="210">
    <param name="person" value="Konishiki">
    <param name="weight" value="605">
</applet>

表達式的用途:更改變量的值;計數;使用數學公式。

Vector

Vector相似python的列表,長度可變。

import java.util.*;

public class StringLister {
    String[] names = { "Spanky", "Alfalfa", "Buckwheat", "Daria",
        "Stymie", "Marianne", "Scotty", "Tommy", "Chubby" };

    public StringLister(String[] moreNames) {
        Vector<String> list = new Vector<String>();
        for (int i = 0; i < names.length; i++) {
            list.add(names[i]);
        }
        for (int i = 0; i < moreNames.length; i++) {
            list.add(moreNames[i]);
        }
        Collections.sort(list);
        for (String name : list) {
            System.out.println(name);
        }
    }

    public static void main(String[] args) {
        StringLister lister = new StringLister(args);
    }
}

 

多線程

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class PrimeFinder extends JFrame implements Runnable, ActionListener {
    Thread go;
    JLabel howManyLabel;
    JTextField howMany;
    JButton display;
    JTextArea primes;

    PrimeFinder() {
        super("Find Prime Numbers");
        setLookAndFeel();
        setSize(400, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        BorderLayout bord = new BorderLayout();
        setLayout(bord);
       
        howManyLabel = new JLabel("Quantity: ");
        howMany = new JTextField("400", 10);
        display = new JButton("Display primes");
        primes = new JTextArea(8, 40);
        
        display.addActionListener(this);         
        JPanel topPanel = new JPanel();
        topPanel.add(howManyLabel);
        topPanel.add(howMany);
        topPanel.add(display);
        add(topPanel, BorderLayout.NORTH);
        
        primes.setLineWrap(true);
        JScrollPane textPane = new JScrollPane(primes);
        add(textPane, BorderLayout.CENTER);
        
        setVisible(true);
    }

    public void actionPerformed(ActionEvent event) {
        display.setEnabled(false);
        if (go == null) {
            go = new Thread(this);
            go.start();
        }
    }

    public void run() {
        int quantity = Integer.parseInt(howMany.getText());
        int numPrimes = 0;
        // candidate: the number that might be prime
        int candidate = 2;
        primes.append("First " + quantity + " primes:");
        while (numPrimes < quantity) {
            if (isPrime(candidate)) {
                primes.append(candidate + " ");
                numPrimes++;
            }
            candidate++;
        }
    }

    public static boolean isPrime(int checkNumber) {
        double root = Math.sqrt(checkNumber);
        for (int i = 2; i <= root; i++) {
            if (checkNumber % i == 0) {
                return false;
            }
        }
        return true;
    }

    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
            );
        } catch (Exception exc) {
            // ignore error
        }
    }
    public static void main(String[] arguments) {
        PrimeFinder fp = new PrimeFinder();
    }
}

 

基於Applet的多線程實例:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
public class LinkRotator extends JApplet
    implements Runnable, ActionListener {
    String[] pageTitle = new String[6];
    URL[] pageLink = new URL[6];
    Color butterscotch = new Color(255, 204, 158);
    int current = 0;
    Thread runner;
    public void init() {
        pageTitle = new String[] {
            "Sun's Java site",
            "Cafe au Lait",
            "JavaWorld",
            "Java in 24 Hours",
            "Sams Publishing",
            "Workbench"
        };
        pageLink[0] = getURL("http://java.sun.com");
        pageLink[1] = getURL("http://www.ibiblio.org/javafaq");
        pageLink[2] = getURL("http://www.javaworld.com");
        pageLink[3] = getURL("http://www.java24hours.com");
        pageLink[4] = getURL("http://www.samspublishing.com");
        pageLink[5] = getURL("http:// workbench.cadenhead.org");
        Button goButton = new Button("Go");
        goButton.addActionListener(this);
        FlowLayout flow = new FlowLayout();
        setLayout(flow);
        add(goButton);
    }
    URL getURL(String urlText) {
        URL pageURL = null;
        try {
            pageURL = new URL(getDocumentBase(), urlText);
        } catch (MalformedURLException m) { }
        return pageURL;
    }
    public void paint(Graphics screen) {
        Graphics2D screen2D = (Graphics2D) screen;
        screen2D.setColor(butterscotch);
        screen2D.fillRect(0, 0, getSize().width, getSize().height);
        screen2D.setColor(Color.black);
        screen2D.drawString(pageTitle[current], 5, 60);
        screen2D.drawString("" + pageLink[current], 5, 80);
    }
    public void start() {
        if (runner == null) {
            runner = new Thread(this);
            runner.start();
        }
    }
    public void run() {
        Thread thisThread = Thread.currentThread();
        while (runner == thisThread) {
            current++;
            if (current > 5) {
                current = 0;
            }
            repaint();
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // do nothing
            }
        }
    }
    public void stop() {
        if (runner != null) {
            runner = null;
        }
    }
    public void actionPerformed(ActionEvent event) {
        if (runner != null) {
            runner = null;
        }
        AppletContext browser = getAppletContext();
        if (pageLink[current] != null) {
            browser.showDocument(pageLink[current]);
        }
    }
}

 

文件讀寫

相關文章
相關標籤/搜索