一淹禾、Lambda表達(dá)式
Lambda表達(dá)式引入了一個(gè)新的操作符" -> "积瞒。Lambda表達(dá)式將函數(shù)當(dāng)成參數(shù)傳遞給某個(gè)方法较屿,或是把代碼本身當(dāng)作數(shù)據(jù)處理。
Lambda表達(dá)式分為兩部分:
() -> { //執(zhí)行的功能 }
左側(cè):Lambda表達(dá)式的參數(shù)列表
右側(cè):Lambda表達(dá)式中所需要執(zhí)行的功能
1筋岛、Lambda表達(dá)式格式
下面講解Lambda的寫(xiě)法:
- Lambda表達(dá)式參數(shù)列表的數(shù)據(jù)類型可以省略不寫(xiě)娶视,JVM編譯器能通過(guò)上下文推斷出來(lái)
void test(){
(x,y) -> { //語(yǔ)句 }
(String x,String y) -> { //語(yǔ)句 }
}
上面兩種寫(xiě)法時(shí)一樣的。
- 無(wú)參數(shù)睁宰、無(wú)返回值
() -> { //語(yǔ)句 }
-
有一個(gè)參數(shù)歇万,無(wú)返回值
當(dāng)只有一個(gè)參數(shù)時(shí),小括號(hào)可以不寫(xiě)勋陪。
(x) -> { //語(yǔ)句 }
x -> { //語(yǔ)句 }
上面兩句等價(jià)贪磺。
-
有兩個(gè)參數(shù)或多個(gè)參數(shù),有返回值
當(dāng)Lambda表達(dá)式中只有一條語(yǔ)句時(shí)诅愚,則大括號(hào)和return
都可以省略寒锚。
(x,y) -> x + y;
當(dāng)Lambda表達(dá)式中有多條語(yǔ)句時(shí),需加上大括號(hào)和return
违孝。
(x,y) -> {
int i = x + y;
System.out.println(i);
return i;
}
2刹前、Lambda表達(dá)式使用
void test(){
//不使用Lambda表達(dá)式
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("不使用Lambda表達(dá)式方式--->hello");
}
};
r.run;
//使用Lambda表達(dá)式
Runnable runnable = () -> System.out.println("使用Lambda表達(dá)式方式--->hello");
runnable.run;
}
上面的例子介紹了使用Lambda表達(dá)式和不使用時(shí)的區(qū)別。
3雌桑、Lambda表達(dá)式需要函數(shù)式接口的支持
- 什么是函數(shù)式接口
函數(shù)式接口:接口中只有一個(gè)抽象方法的接口喇喉,稱為函數(shù)式接口⌒?樱可以使用注解@FunctionalInterface標(biāo)注拣技,此注解可以檢查接口是否是函數(shù)式接口,此注解可以加也可以不加耍目。
java中給我們提供了一些函數(shù)式接口膏斤,我們也可以自定義函數(shù)式接口,下面先舉個(gè)自定義函數(shù)式接口的例子邪驮,接著再講解java給我們提供的部分函數(shù)式接口莫辨。
/**自定義函數(shù)式接口*/
@FunctionalInterface
public interface HandleData<T> {
public T handle(T t);
}
下面是自定義函數(shù)接口的使用:
需求:計(jì)算數(shù)組中元素的和,正常情況步驟如下:
int[] ints = {1,2};
HandleData<int[]> h = new HandleData<int[]>() {
@Override
public Object handle(int[] ints) {
return ints[0] + ints[1];
}
};
//調(diào)用handle方法,將數(shù)組ints傳進(jìn)去沮榜,獲得計(jì)算結(jié)果
int result = (int) h.handle(ints);
接下來(lái)我們來(lái)看看使用Lambda表達(dá)式的寫(xiě)法:
int[] ints = {1,2};
HandleData<int[]> h = (arr) -> arr[0] + arr[1];
int result = (int) h.handle(ints);
上面代碼中的(arr) -> arr[0] + arr[1];
其實(shí)就是重寫(xiě)的handle(int[] ints)
方法盘榨。是不是用Lambda表達(dá)式更簡(jiǎn)潔一些,但是需要注意的是Lambda表達(dá)式需要函數(shù)式接口的支持蟆融。
- java給我們提供的部分函數(shù)式接口:
Function<T,R>:函數(shù)型接口.
??R apply(T t);
??T作為輸入较曼,返回的R作為輸出,輸入和返回的類型可以一致,T振愿、R可以不一致。
int i = 0;
//如果需要處理的代碼是多行弛饭,就需要加大括號(hào)
Function<Integer,Integer> fun = (x) -> x + 1;
int result = fun.apply(i);
Predicate<T>:判斷型接口冕末。
??boolean test(T t);
??T作為輸入,返回boolean值的輸出侣颂。
Consumer<T>:消費(fèi)型接口档桃。
? void accpet(T t);
? T作為輸入沒(méi)有輸出。
Supplier<T>:供給型接口憔晒。
? T get();
? 沒(méi)有輸入藻肄,T作為輸出。
BinaryOperator<T>:二元運(yùn)算型接口拒担。
? R apply(T t, U u);
? 兩個(gè)T作為輸入嘹屯,T同樣是輸出,是BiFunction的子接口。
UnaryOperator<T>:一元運(yùn)算型接口从撼。
? T apply(T t);
? 是Function的變種州弟,輸入輸出者都是T,與Function區(qū)別是低零,UnaryOperator輸入和返回的類型一致婆翔,在此種情況下可以使用UnaryOperator替換Function。
4掏婶、方法引用和構(gòu)造器引用
方法引用:若Lambda體中的功能有方法以及實(shí)現(xiàn)了啃奴,我們可以使用"方法引用",可以理解為方法引用是Lambda表達(dá)式的另外一種表現(xiàn)形式
使用條件:方法引用所引用的方法的參數(shù)列表和返回值必須和函數(shù)式接口中抽象方法的參數(shù)列表和返回值完全一致雄妥。
語(yǔ)法格式:主要有三種
對(duì)象::實(shí)例方法名 ---> Object::method
類名::靜態(tài)方法名 ---> ClassName::static method
類名::實(shí)例方法名--->ClassName::method
注意:
類::靜態(tài)方法名
與類::實(shí)例方法名
的區(qū)別:?
類::實(shí)例方法名
方式中Lambda的第一個(gè)參數(shù)是實(shí)例方法的調(diào)用者最蕾,例如:x,第二個(gè)參數(shù)(或無(wú)參)是實(shí)例方法的參數(shù)老厌,例如:y (參見(jiàn)下面ClassName::method中的代碼所示)揖膜。
下面看代碼來(lái)看如何使用:
- Object::method
Employee emp = new Employee("name",18);
//獲取Employee中的age,因?yàn)間etAge()方法沒(méi)有輸入只有輸出梅桩,我們可以選擇供給型接口Supplier<R>供給型接口壹粟。接口方法:T get();Employee類中獲取年齡方法:int getAge();
Supplier<Integer> sup = () -> emp.getAge();
System.out.println("Lambda表達(dá)式方式:" + sup.get());
//emp對(duì)象::getAge
Supplier<Integer> supplier = emp::getAge;
System.out.println("方法引用方式:" + supplier.get());
- ClassName::static method
//Integer類的compare方法
Comparator<Integer> c = (x,y) -> Integer.compare(x,y);
System.out.println("Lambda表達(dá)式方式:" + c.compare(1,2));
//Integer類名::compare
Comparator<Integer> com = Integer::compare;
System.out.println("方法引用方式:" + com.compare(1,2));
- ClassName::method
BiPredicate<String ,String > b = (x, y) -> x.equals(y);
System.out.println("Lambda表達(dá)式方式:" + b.test("a","b"));
BiPredicate<String ,String > bip = String::equals;
System.out.println("方法引用方式:" + bip.test("a","b"));
構(gòu)造器引用:構(gòu)造器能與函數(shù)式接口中的方法相兼容。
語(yǔ)法格式:
- 類名::new--->ClassName::new
使用條件:構(gòu)造器參數(shù)列表與函數(shù)式接口中抽象方法的參數(shù)列表一致。
//默認(rèn)無(wú)參構(gòu)造器
Supplier<Employee> s = () -> new Employee();
System.out.println("Lambda表達(dá)式方式:" + s.get());
Supplier<Employee> sup = Employee::new;
System.out.println("構(gòu)造器引用方式:" + sup.get());
//有參數(shù)構(gòu)造器,也可以使用BiFunction或是自己寫(xiě)函數(shù)式接口來(lái)實(shí)現(xiàn)兩個(gè)或多個(gè)構(gòu)造器引用
Function<String,Employee> f = (x) -> new Employee(x);
System.out.println("Lambda表達(dá)式方式:" + f.apply("z"));
Function<String,Employee> fun = Employee::new;
System.out.println("構(gòu)造器引用方式:" + fun.apply("z"));
//數(shù)組引用
Function<Integer,String[]> a = (x) -> new String[x];
System.out.println("Lambda表達(dá)式方式:" + a.apply(10).length);
Function<Integer,String[]> arr = String[]::new;
System.out.println("數(shù)組引用方式:" + arr.apply(10).length);
二趁仙、Stream流
1洪添、Stream流是什么?
是數(shù)據(jù)渠道雀费,用于操作數(shù)據(jù)源(集合干奢、數(shù)組等)所生成的元素序列。
- Stream不會(huì)存儲(chǔ)元素盏袄。
- Stream不會(huì)改變?cè)磳?duì)象忿峻。它會(huì)返回一個(gè)持有結(jié)果的新Stream。
- Stream操作是延遲執(zhí)行的辕羽。它會(huì)等到需要結(jié)果的時(shí)候才執(zhí)行逛尚。
2、Stream的操作步驟
- 創(chuàng)建Stream:從一個(gè)數(shù)據(jù)源刁愿、集合绰寞、數(shù)組中獲取流。
- 中間操作:一個(gè)操作的中間鏈铣口,對(duì)數(shù)據(jù)源的數(shù)據(jù)進(jìn)行操作滤钱。
- 終止操作(終端操作):一個(gè)終止操作,執(zhí)行中間操作鏈脑题,并產(chǎn)生結(jié)果件缸。
3、創(chuàng)建Stream流的方式
-
通過(guò)Collection系列集合提供的串行流stream()方法或并行流parallelStream()方法進(jìn)行創(chuàng)建
List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); Stream<String> parallelStream = list.parallelStream();
-
通過(guò)Arrays中的靜態(tài)方法stream()方法
Employee[] emps = new Employee[10]; Stream<Employee> stream = Arrays.stream(emps);
-
通過(guò)Stream接口中的靜態(tài)方法of()
Stream<Employee> emps1 = Stream.of(emps);
-
通過(guò)Stream提供的iterate()和generate()創(chuàng)建無(wú)限流
-
Stream<T> iterate(final T seed, final UnaryOperator<T> f)
T seed:初始元素叔遂。
UnaryOperator<T> f:一元運(yùn)算型接口停团,輸入和輸出者都需要一樣,對(duì)seed進(jìn)行運(yùn)算掏熬。
方法含義:返回一個(gè)無(wú)限有序的流佑稠,以seed為種子,以f為迭代方法旗芬,產(chǎn)生的一個(gè)由seed舌胶,f(seed),f(f(seed))等組成的Stream疮丛,也就是位置n的元素幔嫂,是由位置n-1的元素通過(guò)f方法產(chǎn)生的。
Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2); stream.forEach(System.out::println); //以0為基礎(chǔ)誊薄,以2遞增履恩,一直
-
Stream<T> generate(Supplier<T> s)
Supplier<T> s:供給型接口,沒(méi)有輸入呢蔫,T作為輸出
方法含義:返回一個(gè)無(wú)限無(wú)序的流切心,其中每個(gè)元素都由Supplier生成飒筑,適用于生成恒定元素流、隨機(jī)元素流等绽昏。
Stream<Double> stream = Stream.generate(() -> Math.random()); stream.forEach(System.out::println);
-
4协屡、中間操作-篩選切片
filter(Predicate p)
,limit(long maxSize)
全谤,skip(long n)
肤晓,distinct()
,下面介紹這四個(gè)方法:
//class Employee {name,age,salary}
List<Employee> list = Arrays.asList(new Employee("emp1",1,1000.00),new Employee("emp2",2,2000.00),new Employee("emp3",3,3000.00),new Employee("emp4",4,4000.00),new Employee("emp4",4,4000.00),
);
- filter(Predicate p):接收Lambda认然,從流中排除某些元素补憾。
Stream<Employee> stream = empList.stream()
.filter((e) -> {
return e.getAge() > 2;
});
//只會(huì)顯示年齡大于2的
- limit(long maxSize):截?cái)嗔鳎蛊湓夭怀^(guò)給定數(shù)量卷员。
Stream<Employee> stream = empList.stream()
.limit(2);
//只會(huì)得到前兩條
- skip(long n):跳過(guò)元素盈匾,返回一個(gè)扔掉了前n個(gè)元素的流。若流中元素不足n個(gè)子刮,則返回一個(gè)空流。與limit(n)互補(bǔ)
Stream<Employee> stream = empList.stream()
.skip(2);
//只會(huì)得到后兩條
- distinct():篩選窑睁,通過(guò)流所生成元素的hashCode()和equals()去除重復(fù)元素
Stream<Employee> stream = empList.stream()
.distinct();
//會(huì)去除掉最后一個(gè)new Employee("emp4",4,4000.00)的數(shù)據(jù)
distinct()
方法是根據(jù)元素的hashCode()和equals()的規(guī)則來(lái)判斷元素是否重復(fù)的挺峡,所以如果有需求就重寫(xiě)這兩個(gè)方法。
5担钮、中間操作-映射
map(Function f)
橱赠,mapToDouble(ToDoubleFunction f)
,mapToInt(ToIntFunction f)
箫津,mapToLong(ToLongFunction f)
狭姨,flatMap(Function f)
,下面介紹這五個(gè)方法:
- map(Function f):接收一個(gè)函數(shù)作為參數(shù)苏遥,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上饼拍,并將其映射成一個(gè)新的元素
//class StreamTest03
List<String> list = Arrays.asList("aa","bb");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
//結(jié)果:AA BB
//
Stream<Stream<Character>> characterStream = list.stream()
.map(StreamTest03::filterCharacter);//結(jié)果:a a b b
//如何遍歷characterStream,Stream<Stream<Character>>里的數(shù)據(jù):{{a,a},{b,b}}
characterStream.forEach( (stream) -> {
stream.forEach(System.out::println);
});
//將字符串拆成char然后存到list的方法
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
- mapToDouble(ToDoubleFunction f):接收一個(gè)函數(shù)作為參數(shù)田炭,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上师抄,產(chǎn)生一個(gè)新的DoubleStream
List<Double> list = Arrays.asList(1.1,2.2);
list.stream().mapToDouble((d) -> d+1).forEach(System.out::println);
//結(jié)果:2.1 3.1
- mapToInt(ToIntFunction f):接收一個(gè)函數(shù)作為參數(shù),該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上教硫,產(chǎn)生一個(gè)新的IntStream
- mapToLong(ToLongFunction f):接收一個(gè)函數(shù)作為參數(shù)叨吮,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,產(chǎn)生一個(gè)新的LongStream
- flatMap(Function f):接收一個(gè)函數(shù)作為參數(shù)瞬矩,將流中的每個(gè)值都換成另一個(gè)流茶鉴,然后把所有流連接成一個(gè)流
Stream<Character> cStream = list.stream()
.flatMap(StreamTest03::filterCharacter);//{a,a,b,b}
cStream.forEach(System.out::println);//結(jié)果:a a b b
如上代碼所示,和map(Function f)
的區(qū)別是它會(huì)把所有的連接成一個(gè)流景用。
6涵叮、中間操作-排序
sorted()
,sorted(Comparator comp)
,下面介紹這兩個(gè)方法:
- sorted():產(chǎn)生一個(gè)新流围肥,其中按自然順序排序(Comparable)
List<String> list = Arrays.asList("bb","aa","cc");
list.stream()
.sorted()
.forEach(System.out::println);
//結(jié)果:aa bb cc
- sorted(Comparator comp):產(chǎn)生一個(gè)新流剿干,其中按比較器順序排序(Comparator)
//list是上面的List<Employee>
list.stream()
.sorted((e1,e2) -> {
if (e1.getAge() == e2.getAge()) { //如果年齡相等則根據(jù)名字排序
return e1.getName().compareTo(e2.getName());
}else {
return e2.getAge() - e1.getAge(); //年齡不等從大往小排序
}
})
.forEach(System.out::println);
//結(jié)果:4 4 3 2 1
7、終止操作-查找與匹配
直接介紹有哪些方法穆刻,例子就不列舉了置尔。
- boolean allMatch(Predicate p):檢查是否匹配所有元素。如果都匹配或流為空氢伟,返回true榜轿。
- boolean anyMatch(Predicate p):檢查是否至少匹配一個(gè)元素。
- boolean noneMatch(Predicate p):檢查是否沒(méi)有匹配所有元素朵锣。如果沒(méi)有任何元素匹配或流為空谬盐,返回true。
- Optional<T> findFirst():返回第一個(gè)元素诚些。
- Optional<T> findAny():返回當(dāng)前流中的任意元素飞傀。
- long count():返回流中元素的總個(gè)數(shù)。
- Optional<T> min(Comparator<? super T> comparator):返回流中的最小值诬烹。
- Optional<T> max(Comparator<? super T> comparator):返回流中的最大值砸烦。
8、歸約reduce
-
T reduce(T identity, BinaryOperator<T> accumulator):可以將流中元素反復(fù)結(jié)合起來(lái)绞吁,得到一個(gè)值幢痘。
- T identity:起始值。
- BinaryOperator<T> accumulator:二元運(yùn)算型接口家破。
List<Integer> list = Arrays.asList(1,2,3,4,5);
Integer reduce = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(reduce);
//結(jié)果:15
其實(shí)它是將identity
這個(gè)起始值作為上面代碼中的x
颜说,然后從流中取出一個(gè)作為y
,然后進(jìn)行x+y
運(yùn)算汰聋。
- Optional<T> reduce(BinaryOperator<T> accumulator):可以將流中元素反復(fù)結(jié)合起來(lái)门粪,得到一個(gè)值。因?yàn)闆](méi)有初始值可能為空烹困,所以將結(jié)果封裝到Optional中去庄拇。
Optional<Integer> op1 = list.stream().reduce((x, y) -> x - y);
System.out.println(op1.get());
//結(jié)果:-13
Optional<Empoyee> op2 = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op2.get());
//可以得到工資的總和
9、收集collect
-
<R, A> R collect(Collector<? super T, A, R> collector):
collect
將流轉(zhuǎn)換成其他形式韭邓。接收一個(gè)Collector
接口的實(shí)現(xiàn)措近,用于Stream中元素做匯總的方法。
Collector
接口中方法的實(shí)現(xiàn)決定了如何對(duì)流執(zhí)行收集操作(如收集到List女淑、Set瞭郑、Map)。
public interface Collector<T, A, R> {} 中:
T:歸約操作的輸入元素的類型
A:歸約操作的可變累積類型(通常作為一個(gè)實(shí)現(xiàn)細(xì)節(jié)隱藏)
R:歸約操作結(jié)果的類型
Collectors
類是Collector的實(shí)現(xiàn)鸭你,它實(shí)現(xiàn)了各種有用的歸約操作屈张,例如將元素累積到集合中擒权,根據(jù)各種標(biāo)準(zhǔn)對(duì)元素進(jìn)行匯總等。提供了很多靜態(tài)方法阁谆,可以方便的創(chuàng)建常見(jiàn)收集器實(shí)例碳抄,具體方法與實(shí)例如下表:
方法 | 返回值類型 | 作用 |
---|---|---|
toList() | List<T> | 把流中元素收集到list |
toSet() | Set<T> | 把流中元素收集到set |
toCollection(Supplier s) | Collection<T> | 把流中的元素收集到創(chuàng)建的集合 |
counting() | Long | 計(jì)算流中元素的個(gè)數(shù) |
summingInt(ToIntFunction mapper) | Integer | 對(duì)流中元素的整數(shù)屬性求和 |
averagingInt(ToIntFunction mapper) | Double | 計(jì)算流中元素Integer屬性的平均值 |
summarizingInt(ToIntFunction mapper) | IntSummaryStatistics | 收集流中Integer屬性的統(tǒng)計(jì)值〕÷蹋可通過(guò)返回的對(duì)象獲取平均值等 |
joining() | String | 連接流中每個(gè)字符串 |
maxBy(Comparator com) | Optional<T> | 根據(jù)比較器選擇最大值 |
minBy(Comparator com) | Optional<T> | 根據(jù)比較器選擇最小值 |
collectingAndThen(Collector c,Function f) | f返回的類型 | 包裹另一個(gè)收集器剖效,對(duì)其結(jié)果轉(zhuǎn)換函數(shù) |
groupingBy(Function classifier) | Map<K,List<T>> | 根據(jù)某屬性值對(duì)流分組,屬性為K焰盗,結(jié)果為V |
partitioningBy(Predicate p) | Map<Boolean,List<T>> | 根據(jù)true或false進(jìn)行分區(qū) |
暫且介紹上面幾個(gè)方法璧尸,更多方法可以去看JDK8的API。
下面以Collectors
的collectingAndThen
為例來(lái)介紹collect方法
的使用熬拒。
Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,Function<R,RR> finisher)方法:
此方法中泛型:
- <T>:輸入元素的類型
- <A>: downstream收集器中的中間積累的類型
- <R>: downstream收集器的結(jié)果的類型
- <RR>: 結(jié)果收集器的結(jié)果的類型
方法有兩個(gè)參數(shù):
- Collector<T,A,R> downstream:對(duì)數(shù)據(jù)進(jìn)行處理
- Function<R,RR> finisher:對(duì)downstream收集器最終的結(jié)果再處理一下
返回值:downstream收集器的操作完成后爷光,最終的結(jié)果再通過(guò)Function再處理一下,然后返回一個(gè)Collector澎粟。
說(shuō)明:finisher
是對(duì)downstream
的結(jié)果進(jìn)行處理蛀序,finisher
接口的參數(shù)是downstream
的結(jié)果。collectingAndThen
方法的返回值是finisher
中返回的值活烙。
//List<Employee> list
Employee collect = list.stream()
.collect(Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(Employee::getName)),
(e) -> e.get()
));
List<String> list = Arrays.asList("a","b");
String str = list.stream()
.collect(Collectors.collectingAndThen(
Collectors.joining(","),
String::toUpperCase
));
//結(jié)果是:A,B
上面代碼溉知,downstream
先用joining
方法將字符串連接成:"a,b"
卒落,然后將使用String::toUpperCase
對(duì)"a,b"
轉(zhuǎn)大寫(xiě)儒鹿。
三唬涧、Optional類
Optional<T>
類(java.util.Optional
)是一個(gè)容器類譬正,代表一個(gè)值存在或不存在宫补,原來(lái)用null
表示一個(gè)值不存在,現(xiàn)在Optional
可以更好的表達(dá)這個(gè)概念曾我。并且可以避免空指針粉怕。
常用方法:
Optional.of(T t):創(chuàng)建一個(gè)Optional實(shí)例
Optional.empty():創(chuàng)建一個(gè)空的Optional實(shí)例
Optional.ofNullable(T t):若t不為null,創(chuàng)建Optional實(shí)例抒巢,否則創(chuàng)建空實(shí)例
isPresent():判斷是否包含空值贫贝,空返回false
orElse(T t):如果調(diào)用對(duì)象包含值,返回該值蛉谜,否則返回t
orElseGet(Supplier s):如果調(diào)用對(duì)象包含值稚晚,返回該值,否則返回s獲取的值
map(Function f):如果有值對(duì)其處理型诚,并返回處理后的Optional客燕,否則返回Optional.empty()
flatMap(Function mapper):與map類似,要求返回值必須是Optional
四狰贯、接口中的默認(rèn)方法和靜態(tài)方法
1也搓、接口中的默認(rèn)方法
java8中接口里面包含具體的實(shí)現(xiàn)方法赏廓,該方法稱為默認(rèn)方法,默認(rèn)方法使用default
關(guān)鍵字修飾傍妒。
public interface MyInterface {
default String getName(){
return "MyInterface";
}
}
對(duì)于默認(rèn)的方法幔摸,遵循的原則:
若一個(gè)接口中定義了一個(gè)默認(rèn)方法,另一個(gè)的父類或接口中又定義一個(gè)同名方法時(shí):
- 選擇父類中的方法颤练。如果一個(gè)父類提供了具體實(shí)現(xiàn)既忆,那么接口中具有相同名稱和參數(shù)的默認(rèn)方法會(huì)被忽略
public class MyClass {
public String getName(){
return "MyClass";
}
}
public interface MyInterface {
default String getName(){
return "MyInterface";
}
}
public class SubClass extends MyClass implements MyInterface {}
SubClass sub = new SubClass();
String name = sub.getName();
System.out.println(name);
//MyClass
- 接口沖突。如果一個(gè)父接口提供一個(gè)默認(rèn)方法昔案,而另一個(gè)接口也提供了一個(gè)具有相同名稱和參數(shù)列表的方法(不管方法是否是默認(rèn)方法)尿贫,那么必須覆蓋該方法來(lái)解決沖突
public interface MyInterface2 {
default String getName(){
return "MyInterface2";
}
}
public class SubClass implements MyInterface1,MyInterface2{
@Override
public String getName() {
return "SubClass重寫(xiě)該方法";
}
}
如上代碼,實(shí)現(xiàn)類SubClass
里要重寫(xiě)該方法解決沖突踏揣。
2庆亡、接口中的靜態(tài)方法
public interface MyInterface1 {
default String getName(){
return "MyInterface1";
}
public static void show(){
System.out.println("接口中的靜態(tài)方法");
}
}
MyInterface1.show();
//接口中的靜態(tài)方法
五、新時(shí)間日期API
JDK8新增的時(shí)間API主要有三種:
java.time.LocalDate:只對(duì)年月日做出處理
java.time.LocatTime:只對(duì)時(shí)分秒納秒做出處理
java.time.LocalDateTime:同時(shí)可以處理年月日和時(shí)分秒
java.time.format.DateTimeFormatter:日期時(shí)間對(duì)象格式化和解析
1捞稿、LocalDate又谋、LocalTime、LocalDateTime
LocalDate娱局、LocalTime彰亥、LocalDateTime 類的實(shí)例是不可變的對(duì)象,分別表示使用 ISO-8601日系統(tǒng)的日期衰齐、時(shí)間任斋、日期和時(shí)間。它們提供了簡(jiǎn)單的日期或時(shí)間耻涛,并不包含當(dāng)前的時(shí)間信息废酷。也不包含與時(shí)區(qū)相關(guān)的信息。
方法 | 描述 | 示例 |
---|---|---|
now() | 靜態(tài)方法抹缕,根據(jù)當(dāng)前時(shí)間創(chuàng)建對(duì)象 | LocalDate.now();<br />LocalTime.now();<br />LocalDateTime.now(); |
of() | 靜態(tài)方法澈蟆,根據(jù)指定日期/時(shí)間創(chuàng)建對(duì)象 | LocalDate.of(2020,01,01); |
plusDays<br />plusWeeks plusMonths plusYears |
向當(dāng)前LocalDate對(duì)象添加幾天、幾周卓研、幾個(gè)月趴俘、幾年 | |
minusDays<br />minusWeeks minusMonths minusYears |
從當(dāng)前LocalDate對(duì)象減去幾天、幾周奏赘、幾個(gè)月寥闪、幾年 | |
plus,minus | 添加或減去一個(gè)Duration或Period | |
with | 通過(guò)TemporalAdjuster將日期修改為指定的值,并返回新的LocalDate對(duì)象 | |
withDayOfMonth withDayOfYear withMonth withYear |
將月份天數(shù)磨淌,年份天數(shù)疲憋,月份,年份修改為指定的值并返回新的LocalDate對(duì)象 | |
getDayOfMonth | 獲得月份天數(shù)(1-31) | |
getDayOfYear | 獲得年份天數(shù)(1-366) | |
getDayOfWeek | 獲得星期幾(返回一個(gè)DayOfWeek枚舉值) | |
getMonth | 獲得月份伦糯,返回一個(gè)Month枚舉值 | |
getMonthValue | 獲得月份(1-12) | |
getYear | 獲得年份 | |
until | 獲得兩個(gè)日期之間的Period對(duì)象柜某,或者指定ChronoUnits的數(shù)字 | |
isBefore,isAfter | 比較兩個(gè)LocalDate | |
isLeapYear | 判斷是否是閏年 |
2嗽元、Instant時(shí)間戳
用于“時(shí)間戳”的運(yùn)算。它是以Unix元年(傳統(tǒng)的設(shè)定為UTC時(shí)區(qū)1970年1月1日午夜時(shí)分)開(kāi)始所經(jīng)歷的描述進(jìn)行運(yùn)算喂击,默認(rèn)UTC時(shí)區(qū)剂癌。
- 獲取當(dāng)前時(shí)間:
Instant.now();
返回當(dāng)前時(shí)間,默認(rèn)獲取UTC時(shí)區(qū) - 調(diào)整偏移量:
Instant.now().atoffset(ZoneOffset.ofHours(8));
調(diào)整為北京時(shí)間 - 獲取毫秒數(shù):
Instant.now().toEpochMilli();
獲取時(shí)間戳
3翰绊、Duration和Period計(jì)算時(shí)間/日期間隔
- Duration:用于計(jì)算兩個(gè)“時(shí)間”間隔
Instant start = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant end = Instant.now();
Duration d = Duration.between(start, end);
d.toMillis();//獲取相差的毫秒
d.toMillis();//獲取相差的秒
- Period:用于計(jì)算兩個(gè)“日期”間隔
LocalDate old = LocalDate.of(2019,10,1);
LocalDate now = LocalDate.now();//2020-10-01
Period p = Period.between(old, now);
p.getYears();//兩個(gè)日期之間間隔的年佩谷,結(jié)果為:1
p.getMonths();//兩個(gè)日期之間間隔的月,結(jié)果為:0
p.getDays();//兩個(gè)日期之間間隔的日监嗜,結(jié)果為:0
//這三個(gè)加起來(lái)就是兩個(gè)日期之間相差的時(shí)間
4谐檀、TemporalAdjuster時(shí)間校正器
TemporalAdjuster : 時(shí)間校正器。有時(shí)我們可能需要獲取裁奇,例如:將日期調(diào)整到下周一等操作桐猬。
**TemporalAdjusters : **該類通過(guò)靜態(tài)方法提供了大量的常用 TemporalAdjuster 的實(shí)現(xiàn)。
LocalDateTime now = LocalDateTime.now();
now.with(TemporalAdjusters.next(DayOfWeek.MONDAY));//返回以今天為準(zhǔn)的下周一的時(shí)間
自定義方式:
LocalDate result = now.with((time) -> {
LocalDate date = (LocalDate) time;
return date.plusDays(1);
});
//返回下一天的日期
5刽肠、DateTimeFormatter時(shí)間/日期格式化
DateTimeFormatter
是時(shí)間日期格式化的類溃肪,更復(fù)雜的格式化可以使用DateTimeFormatterBuilder
類。
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.append(dtf).appendLiteral(" 星期三");
String format = now.format(dtfb.toFormatter());
//2020-10-01 17:39:33 星期三
這個(gè)類提供了三種格式化方法:
- 使用預(yù)定義的標(biāo)準(zhǔn)格式音五,如ISO_local_date
- 使用語(yǔ)言環(huán)境相關(guān)的格式惫撰,如uuuu-MMM-dd
- 自定義的格式,如long
//格式化
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDate = now.format(dtf);
System.out.println("formatDate--->" + formatDate);//formatDate--->2020-10-01 17:57:00
//解析
LocalDateTime parseDate = now.parse(formatDate, dtf);
System.out.println("parseDate--->" + parseDate);//parseDate--->2020-01-14T17:57
6躺涝、ZonedDateTime厨钻、ZoneId時(shí)區(qū)處理
帶時(shí)區(qū)的時(shí)間分別為:ZonedDate
、ZonedTime
坚嗜、ZonedDateTime
夯膀。
其中每個(gè)時(shí)區(qū)都對(duì)應(yīng)著 ID,地區(qū)ID都為 “{區(qū)域}/{城市}”的格式:例如 :Asia/Shanghai
等惶傻。
ZoneId:該類中包含了所有的時(shí)區(qū)信息
getAvailableZoneIds()
: 可以獲取所有時(shí)區(qū)時(shí)區(qū)信息of(id)
: 用指定的時(shí)區(qū)信息獲取ZoneId
對(duì)象systemDefault()
:獲取系統(tǒng)默認(rèn)時(shí)區(qū)
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime zdt = now.atZone(ZoneId.of("Asia/Shanghai"));
六棍郎、重復(fù)注解與類型注解
對(duì)注解處理提供了兩點(diǎn)改進(jìn):可重復(fù)注解及可用于類型的注解其障。
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,ElementType.TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
@MyAnnotation("Hello")
@MyAnnotation("World")
public void test(@MyAnnotation("a") String str){}