API(application program interface)是指程式之间具有特定规範的接口。透过这些接口可以引用其他程式来协助完成整体机能。
其实JAVA当中引用package或class的概念也与此相同。以下介绍常见的class及其method:
Object是java中所有class的父类。
里面提供了一些通用方法
範例:
class Foo {}class Sample7_1 { public static void main(String[] args) { int[] ary = {1,2,3}; Class obj1 = ary.getClass(); System.out.println(obj1.getName()); Foo foo = new Foo(); Class obj2 = foo.getClass(); System.out.println(obj2.getName()); }}
执行结果
[IFoo
本範例中使用getClass()取得实例化物件的来源class后,再使用getName()方法得到class的名称。
结果的第一行中,"["表示阵列,"I"则表示int型态。合起来即为储存int资料的阵列。
Foo则为class名称。
equals()方法
Object class里面的equals()方法用来比较两个物件是否为同一个。然而在String类中,这个方法却被用来比较值是否相等。
这是因为equals()方法在String类中被覆写了的关係。
下面几个範例,比较equals()在String,StringBuilder及Integer类中的不同。
String类的equals()方法
class Sample7_2 { public static void main(String[] args) { String s1 = "Tom"; String s2 = new String("Tom"); String s3 = "tom"; System.out.println("s1 == s2 : " + (s1 == s2)); System.out.println("s1.equals(s2) : " + s1.equals(s2)); System.out.println("s1.equals(s3) : " + s1.equals(s3)); System.out.println("s1.equalsIgnoreCase(s3) : " + s1.equalsIgnoreCase(s3)); }}
执行结果
s1 == s2 : falses1.equals(s2) : trues1.equals(s3) : falses1.equalsIgnoreCase(s3) : true
说明
s1与s2不是同一个物件,返回false
s1与s2的值相同,返回true
s1与s3的大小写不同,返回false
忽略大小写,返回true
StringBuilder类的equals()方法
class Sample7_3 { public static void main(String[] args) { //StringBuilder sb1 = "Tom"; //error StringBuilder sb2 = new StringBuilder("Tom"); StringBuilder sb3 = new StringBuilder("Tom"); System.out.println("sb2 == sb3 :" + (sb2 == sb3)); System.out.println("sb2.equals(sb3) :" + sb2.equals(sb3)); System.out.println("sb2.toString().equals(sb3.toString()) :" + sb2.toString().equals(sb3.toString())); }}
执行结果
sb2 == sb3 :falsesb2.equals(sb3) :falsesb2.toString().equals(sb3.toString()) :true
说明
"==" 比较是否为同一物件,传回false。
StringBuilder的equals()未被覆写(跟Object类一样),比较是否为同一物件,传回false。
要比较StringBuilder的值,可以运用toString()方法转为String物件后,即可用equals()进行比较,传回true。
Integer类的equals()方法
class Sample7_4 { public static void main(String[] args) { Integer val1 = 1; Integer val2 = 1; System.out.println("val1 == val2 :" + (val1 == val2)); Integer val3 = 150; Integer val4 = 150; System.out.println("val3 == val4 :" + (val3 == val4)); System.out.println("val3.equals(val4) :" + val3.equals(val4)); Integer val5 = new Integer(1); System.out.println("val1 == val5 :" + (val1 == val5)); System.out.println("val1.equals(val5) :" + val1.equals(val5)); Long val6 = new Long(150); Double val7 = new Double(150.0); System.out.println("val3.equals(val6) :" + val3.equals(val6)); System.out.println("val3.equals(val7) :" + val3.equals(val7)); System.out.println("val3.equals(val6.intValue()) :" + val3.equals(val6.intValue())); System.out.println("val3.equals(val7.intValue()) :" + val3.equals(val7.intValue())); }}
执行结果
val1 == val2 :trueval3 == val4 :falseval3.equals(val4) :trueval1 == val5 :falseval1.equals(val5) :trueval3.equals(val6) :falseval3.equals(val7) :falseval3.equals(val6.intValue()) :trueval3.equals(val7.intValue()) :true
说明
第一行比较了val1和val2两个物件是否为同一物件,结果传回true。
这是因为当参照值为int形式,且值介于-128 ~127之间(储存空间小于1 byte),则参照此值的物件,都是参照记忆体上相同的位址,即同一物件。
第二行的值为150,超过了1 byte所能保存的範围,因此不是同一物件。需使用equals()比较值大小,才会传回true(第三行)。
这表示Integer类和String类的equals()方法一样,都被覆写为比较值的方法。
第四行&第五行:使用new()方法新增物件的话,即使值相同也不会被视为同一物件。因此val1和val5不是同物件,但值相同。
第六行以后比较Long,Double及Integer等不同类型的物件,由于无法直接比较,引此传回false。
利用intValue()方法将Long,Double类转为Integer类之后即可进行值的比较。
toString()方法
toString()也是Object提供的基本方法之一,会传回物件的class名+@+hashcode。不过依照各个class需求的不同,通常这方法会被覆写成其他样子。
请看以下範例:
class Foo {}class Bar { public String toString(){ return "This is an object made from Bar."; }}class Sample7_5 { public static void main(String[] args) { String obj1 = "Tom"; StringBuilder obj2 = new StringBuilder("Tom"); Foo obj3 = new Foo(); Bar obj4 = new Bar(); System.out.println(obj1); System.out.println(obj2); System.out.println(obj3); System.out.println(obj4); }}
执行结果
TomTomFoo@368239c8This is an object made from Bar.
说明
String和StringBuilder类的toString()都被覆写过,会传回其保存的文字列。
没被覆写过的toString()会传回物件的class名+@+hashcode。
也可以自定义要传回的文字列。
Math class
提供数学计算的一些方法,例如:
int num1 = 100;
int num2 = 200;
int max = int Math.max(num1,num2); //传回最大值
double randomVal = int Math.random(); //传回小于1的随机值
阵列方法
请看以下範例:
import java.util.*;class Sample7_6 { public static void main(String[] args) { int[] i_array = {30,10,20,50,40}; //使用arraycopy()方法複製阵列 int[] copy = new int[3]; System.arraycopy(i_array,2,copy,0,3); for(int val: copy){ System.out.print(val + " "); }System.out.println(); //使用sort()方法排序 Arrays.sort(i_array); for(int val: i_array){ System.out.print(val + " "); }System.out.println(); //使用asList()方法 String[] s_array = {"Tom","Hill","Cathy"}; List<String> list = Arrays.asList(s_array); //list.add("Mary"); for(String val: list){ System.out.print(val + " "); }System.out.println(); }}
执行结果
20 50 4010 20 30 40 50Tom Hill Cathy
说明
arraycopy()方法属于System类,文法为arraycopy(来源阵列,开始位置,目标阵列,开始位置,複製的长度)
sort()方法属于Arrays类(需先import),可依内容值的大小重新排列阵列。
asList()方法属于Arrays类(需先import),可将阵列转为List(固定长)。由于固定长的List无法增加长度,因此list.add("Mary");这行若执行的话会报错。
需要可变长的列表时,使用ArrayList如下例:
List<String> list = new ArrayList<>(Arrays.asList(s_array));list.add("Mary");
执行结果
Tom Hill Cathy Mary
Date and Time API的基本
此类由java.time包提供,特徵如下:
分别提供日期、时间以及日期+时间等classDate and Time的class为不可修改的物件,因此在多线程环境下可安全使用。提供充足的日期时间计算功能。java.time包的主要class
LocalDateLocalTimeLocalDateTimePeriod(期间)java.time.format包的主要class
DateTimeFomatter(负责日期时间的输出格式)来看看日期时间的範例吧:
import java.time.*;class Sample7_7 { public static void main(String[] args) { LocalDate dateNow = LocalDate.now(); LocalTime timeNow = LocalTime.now(); LocalDateTime dateTimeNow = LocalDateTime.now(); LocalDate dateOf = LocalDate.of(2021,2,25); LocalTime TimeOf = LocalTime.of(21,3,20); LocalDateTime dateTimeOf = LocalDateTime.of(2021,2,25,21,3,20); LocalDate dateP = LocalDate.parse("2021-02-25"); LocalTime TimeP = LocalTime.parse("21:03:20"); LocalDateTime dateTimeP = LocalDateTime.parse("2021-02-25T21:03:20"); System.out.println("LocalDate.now :" + dateNow); System.out.println("LocalTime.now :" + timeNow); System.out.println("LocalDateTime.now :" + dateTimeNow); System.out.println("LocalDate.of :" + dateOf); System.out.println("LocalTime.of :" + TimeOf); System.out.println("LocalDateTime.of :" + dateTimeOf); System.out.println("LocalDate.parse :" + dateP); System.out.println("LocalTime.parse :" + TimeP); System.out.println("LocalDateTime.parse :" + dateTimeP); }}
执行结果
LocalDate.now :2021-02-25LocalTime.now :19:24:11.679136400LocalDateTime.now :2021-02-25T19:24:11.679136400LocalDate.of :2021-02-25LocalTime.of :21:03:20LocalDateTime.of :2021-02-25T21:03:20LocalDate.parse :2021-02-25LocalTime.parse :21:03:20LocalDateTime.parse :2021-02-25T21:03:20
日期格式範例
import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;class Sample7_8 { public static void main(String[] args) { LocalDateTime dt1 = LocalDateTime.now(); DateTimeFormatter fmt1 = DateTimeFormatter.ISO_DATE; System.out.println("now() :" + dt1); System.out.println("ISO_DATE :" + fmt1.format(dt1)); DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); String target = "2021/02/25 21:03:20"; LocalDateTime dt2 = LocalDateTime.parse(target, fmt2); System.out.println("ofPattern() :" + dt2); }}
执行结果
now() :2021-02-25T19:34:43.799818400ISO_DATE :2021-02-25ofPattern() :2021-02-25T21:03:20
说明
ISO_DATE是标準的日期格式,使用DateTimeFormatter.format()方法将目标日期修改为标準格式。
自订格式可用DateTimeFormatter.ofPattern()方法来製作。
再用LocalDateTime.parse(目标日期,自订格式)来套用格式。
日期时间计算範例
import java.time.LocalDate;class Sample7_9 { public static void main(String[] args) { LocalDate date = LocalDate.of(2020,02,25); System.out.println("date :" + date); System.out.println("After 3 day :" + date.plusDays(3)); System.out.println("After 5 months :" + date.plusMonths(5)); System.out.println("After 2 weeks :" + date.plusWeeks(2)); System.out.println("After 10 years :" + date.plusYears(10)); }}
执行结果
date :2020-02-25After 3 day :2020-02-28After 5 months :2020-07-25After 2 weeks :2020-03-10After 10 years :2030-02-25
Collection&Lambda式
函数型interface
定义的抽象方法只有一个(包含static及default方法)的interface,称为函数型interface。
Lambda式
有些class只使用一次而不会在其他地方使用,此时可以不用特别定义class,而採用Lambda式来处理,文法如下:
{引数} -> {处理};
处理后的返回值,会被丢给函数型interface承接。
※函数型interface意指只含有一个抽象方法(或是static,default方法)的interface
请看下例:
import java.util.function.Function;public class Sample7_10 { public static void main(String[] args) { Function<String, String> obj = (String str) -> { return "Hello " + str; }; String str = obj.apply("Tom"); System.out.println(str); }}
执行结果
Hello Tom
此範例中,从Function<String, String> obj 开始的三行程式码,相当于class定义。
在这个匿名class(没有名字的class)中使用了Lambda式{引数} -> {处理},然后把返回值丢给Function<String, String> obj。
Function是一个JAVA提供的函数型interface,因此里面只有一个抽象方法叫做apply()。
我们在Lambda式里面把这个抽象方法给覆写了,内容就是return "Hello " + str;
因此,当obj.apply()方法被执行时,"Tom"作为引数被丢进方法里,加工后返回。
※Function<String, String>的意思是Function<引数的型态, 返回值的型态>
JAVA SE8导入了以下几个函数型interface,有兴趣可以google一下。
Function<T,R>
Consumer
Predicate
Supplier
UnaryOperator
另外Lambda式还有各式各样的简写,範例如下:
未简写
(String str) ->
省略资料型态(因为interface那边已经宣告过了)
(str) ->
省略括号(引数只有一个时可省略)
str ->
没有引数的时候
() ->
接下来看->右边的简写
未简写
{ return "Hello" + str;}
省略中括号和retrun(处理只有一行时)
"Hello" + str;
简写后的範例如下:
import java.util.function.Function;public class Sample7_10 { public static void main(String[] args) { //函数型interface<T,R> obj = 引数 -> 处理内容; Function<String, String> obj = str -> "Hello " + str; String str = obj.apply("Tom"); System.out.println(str); }}
再来看看其他函数型interface的使用範例吧
import java.util.*;import java.util.function.*;public class Sample7_11 { public static void main(String[] args) { List<String> words = Arrays.asList("Tom","Mary"); words.replaceAll( str -> str.toUpperCase()); System.out.println(words); }}
执行结果
[TOM, MARY]
※replaceAll()是List interface提供的default方法
import java.util.*;import java.util.function.*;public class Sample7_12 { public static void main(String[] args) { List<Integer> data = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5)); data.removeIf( i -> i % 2 != 0); System.out.println(data); }}
执行结果
[2, 4]
※removeIf是Collection提供的default方法
以上是第七章 API的学习心得,下一章会介绍例外的处理。
参考教材: JAVAプログラマSilver SE8 - 山本 道子