一喉脖、Lambda表達(dá)式
二腐晾、方法調(diào)用(雙冒號(hào))的用法
三、Stream函數(shù)式操作流元素集合
四 忙厌、接口新增:默認(rèn)方法與靜態(tài)方法
五翩概、最新的Date/Time API
一牲距、Lambda表達(dá)式
1、語(yǔ)法:完整的Lambda表達(dá)式由三部分組成:參數(shù)列表钥庇、箭頭牍鞠、聲明語(yǔ)句
(Type1 param1, Type2 param2, ..., TypeN paramN) -> { statment1; statment2; //............. return statmentM;}
2、絕大多數(shù)情況评姨,編譯器都可以從上下文環(huán)境中推斷出lambda表達(dá)式的參數(shù)類(lèi)型难述,所以參數(shù)可以省略
(param1,param2, ..., paramN) -> { statment1; statment2; //............. return statmentM;}
3、當(dāng)lambda表達(dá)式的參數(shù)個(gè)數(shù)只有一個(gè)吐句,可以省略小括號(hào)
param1 -> { statment1; statment2; //............. return statmentM;}
4胁后、當(dāng)lambda表達(dá)式只包含一條語(yǔ)句時(shí),可以省略大括號(hào)嗦枢、return和語(yǔ)句結(jié)尾的分號(hào)
param1 -> statment
展示例子:
// bean類(lèi)
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Student {
//名字
private String name;
//性別
private String sex;
//薪水
private int salary;
//年齡
private int age;
//星座
private String star;
public static void printStuMethod(Student stu) {
System.out.println("get student, name is: " + stu.getName());
}
}
// 構(gòu)造bean list對(duì)象
List<Student> list = Arrays.asList(
new Student("張三","男",5000,18,"天秤座"),
new Student("李四","男",4000,16,"雙魚(yú)座"),
new Student("王五","男",3000,24,"水瓶座")
);
- list的遍歷
// 標(biāo)準(zhǔn)寫(xiě)法
list.stream().forEach((Student x) -> {System.out.println(x);});
// 簡(jiǎn)略寫(xiě)法
list.stream().forEach(x -> System.out.println(x));
// 雙冒號(hào)簡(jiǎn)略寫(xiě)法
list.stream().forEach(System.out::println);
// 雙冒號(hào)調(diào)用類(lèi)內(nèi)部靜態(tài)方法
list.stream().forEach(Student::printStuMethod);
// 結(jié)合stream的其他方法
list.stream().filter(e -> e.getStar().equals("天秤座")).forEach(System.out::println);
- map的遍歷
// 構(gòu)造map對(duì)象
Map<String, Student> map = Maps.uniqueIndex(list, new Function<Student, String>() {
@Override
public String apply(Student person) {
return person.getName();
}
});
// 輸出方法
public static void printMap(String key, Student value){
System.out.println(key + " " + value);
}
// 標(biāo)準(zhǔn)寫(xiě)法輸出
map.forEach( (k,v) -> System.out.println(k+" "+v) );
// 調(diào)用內(nèi)部方法輸出
map.forEach( (k,v) -> printMap(k, v) );
- set的遍歷
Set<String> sets = Sets.newHashSet("1", "2", "3");
// 輸出方法
public static void printSet(String set){
System.out.println(set);
}
// 寫(xiě)法一
sets.stream().forEach(System.out::println);
// 寫(xiě)法二攀芯,調(diào)用內(nèi)部方法
sets.stream().forEach(x -> printSet(x));
- 帶有返回值的 lambda 用法
標(biāo)準(zhǔn)實(shí)例
// 定義接口
public interface Calculator {
//定義一個(gè)計(jì)算兩個(gè)int整數(shù)和的方法并返回結(jié)果
public abstract int calc(int a,int b);
}
// 調(diào)用
public class DemoCalculator {
public static void main(String[] args) {
//調(diào)用invokeCalc方法,方法的參數(shù)是一個(gè)接口可以使用匿名內(nèi)部類(lèi)
invokeCalc(5, 10, new Calculator() {
@Override
public int calc(int a, int b) {
return a + b;
}
});
//使用Lambda表達(dá)式簡(jiǎn)化匿名內(nèi)部類(lèi)的書(shū)寫(xiě)
invokeCalc(10,20,(int a,int b)->{
return a + b;
});
//優(yōu)化省略L(fǎng)ambda表達(dá)式
invokeCalc(10,20,(a,b)-> a + b);
}
public static void invokeCalc(int a,int b,Calculator c){
int sum = c.calc(a,b);
System.out.println(sum);
}
}
二文虏、方法調(diào)用(雙冒號(hào))的用法
方法調(diào)用的五種形式
- 對(duì)象實(shí)例::實(shí)例方法名
- 對(duì)象實(shí)例名::實(shí)例方法名
- 類(lèi)名::靜態(tài)方法名
- 類(lèi)名::實(shí)例方法名
- 類(lèi)名::new
JDK8中增加了一個(gè)新的包:java.util.function侣诺,它里面包含了常用的函數(shù)式接口,例如:
- Predicate<T>:接收 T 并返回 boolean
- Consumer<T>:接收 T择葡,不返回值
- Function<T, R>:接收 T紧武,返回 R
- Supplier<T>:提供 T 對(duì)象(例如工廠(chǎng))剃氧,不接收值
- UnaryOperator<T>:接收 T 對(duì)象敏储,返回 T
- BinaryOperator<T>:接收兩個(gè) T,返回 T
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class MethodReference {
public MethodReference(String s) {
System.out.println("print ==> " + s);
}
public static void main(String[] args) {
method1();
method2();
method3();
method4();
method5();
}
// 1朋鞍、實(shí)例對(duì)象::實(shí)例方法名
public static void method1(){
Student student = new Student("ZhangSan",23);
Supplier<String> supplier1 = () -> student.getName();
System.out.println("Lambda形式: "+supplier1.get());
Supplier<String> supplier2 = student::getName ;
System.out.println("方法引用形式: "+supplier2.get());
}
// 2已添、實(shí)例對(duì)象名::實(shí)例方法名
public static void method2(){
//傳統(tǒng)的lambda表達(dá)式
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("Hi: 我是Lambda表達(dá)式實(shí)現(xiàn)的妥箕!"); //打印:Hi: 我是Lambda表達(dá)式實(shí)現(xiàn)的更舞!
//方法引用實(shí)現(xiàn)
consumer = System.out::println;
consumer.accept("Hello : ZhangSan畦幢,我是使用方法引用實(shí)現(xiàn)的 ");
}
// 3、類(lèi)名::靜態(tài)方法名
public static void method3(){
//傳統(tǒng)的lambda表達(dá)式
Consumer<String> consumer = (str) -> MethodReference.sayName(str);
consumer.accept("Hello : XiangYang");
//方法引用實(shí)現(xiàn)
consumer = MethodReference::sayName;
consumer.accept("Hello : XiangYang");
}
public static void sayName(String name){
System.out.println(name);
}
// 4缆蝉、類(lèi)名::實(shí)例方法名
// 參數(shù)列表的第一個(gè)參數(shù)是實(shí)例方法的調(diào)用者宇葱, 第n>1個(gè)參數(shù)是實(shí)例方法的參數(shù)時(shí)進(jìn)行使用
public static void method4(){
BiPredicate<String,String> biPredicate = (x , y) -> x.equals(y);
boolean test = biPredicate.test("hello","hi");
System.out.println(test);
biPredicate = String::equals;
test = biPredicate.test("hello","hello");
System.out.println(test);
}
// 5、類(lèi)名::new
public static void method5(){
Consumer<String> consumer = MethodReference::new;
consumer.accept("hello");
}
}
三刊头、Stream函數(shù)式操作流元素集合
父類(lèi):BasicStream
子類(lèi):Stream黍瞧、IntStream、LongStream原杂、DoubleStream
包含兩個(gè)類(lèi)型印颤,中間操作(intermediate operations)和結(jié)束操作(terminal operations)
下面是所有方法的屬于那一端操作的方法:
下面測(cè)試一下map、flatmap穿肄、reduce三個(gè)方法年局,其它方法的用法請(qǐng)參考:
https://my.oschina.net/mdxlcj/blog/1622718
先準(zhǔn)備一個(gè)list
public static List<Student> list = Arrays.asList(
new Student("張三", 12),
new Student("李四", 15),
new Student("王五", 21)
);
- map:將List<Student> 轉(zhuǎn)換為L(zhǎng)ist<String>, collect是將結(jié)果轉(zhuǎn)換為L(zhǎng)ist
List<String> names = list.stream().map(Student::getName).collect(Collectors.toList());
names.stream().forEach(System.out::println);
- mapToInt:轉(zhuǎn)換數(shù)值流,等同mapToLong咸产、mapToDouble矢否,如下這個(gè)是取最大值
IntStream intStream = list.stream().mapToInt(Student::getAge);
Stream<Integer> integerStream = intStream.boxed();
Optional<Integer> max = integerStream.max(Integer::compareTo);
System.out.println(max.get());
- flatMap:將流中的每一個(gè)元素 T 映射為一個(gè)流,再把每一個(gè)流連接成為一個(gè)流
List<String> list2 = new ArrayList<>();
list2.add("aaa bbb ccc");
list2.add("ddd eee fff");
list2.add("ggg hhh iii");
list2 = list2.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(Collectors.toList());
System.out.println(list2);
- reduce reduce(accumulator) :參數(shù)是一個(gè)執(zhí)行雙目運(yùn)算的 Functional Interface脑溢,假如這個(gè)參數(shù)表示的操作為 op兴喂,stream 中的元素為 x, y, z, …,則 reduce() 執(zhí)行的就是 x op y op z ...焚志,所以要求 op 這個(gè)操作具有結(jié)合性(associative)衣迷,即滿(mǎn)足: (x op y) op z = x op (y op z),滿(mǎn)足這個(gè)要求的操作主要有:求和酱酬、求積壶谒、求最大值、求最小值膳沽、字符串連接汗菜、集合并集和交集等。另外挑社,該函數(shù)的返回值是 Optional 的:
Optional <integer>sum1 = numStream.reduce((x, y) -> x + y);
- reduce(identity, accumulator) :可以認(rèn)為第一個(gè)參數(shù)為默認(rèn)值陨界,但需要滿(mǎn)足 identity op x = x,所以對(duì)于求和操作痛阻,identity 的值為 0菌瘪,對(duì)于求積操作,identity 的值為 1。返回值類(lèi)型是 stream 元素的類(lèi)型:
Integer sum2 = numStream.reduce(0, Integer::sum);
- reduce 如果不加參數(shù)identity則返回的是 optional 類(lèi)型的俏扩,reduce 在進(jìn)行雙目運(yùn)算時(shí)糜工,其中一個(gè)場(chǎng)景是與identity做比較操作,因此我們應(yīng)該滿(mǎn)足identity op x = x
Stream<Integer> stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8});
//求集合元素之和
Integer result = stream.reduce(0, Integer::sum);
System.out.println(result);
//求和
stream.reduce((i, j) -> i + j).ifPresent(System.out::println);
//求最大值
stream.reduce(Integer::max).ifPresent(System.out::println);
//求最小值
stream.reduce(Integer::min).ifPresent(System.out::println);
//做邏輯
stream.reduce((i, j) -> i > j ? j : i).ifPresent(System.out::println);
//求邏輯求乘積
int result2 = stream.filter(i -> i % 2 == 0).reduce(1, (i, j) -> i * j);
Optional.of(result2).ifPresent(System.out::println);
四 录淡、接口新增:默認(rèn)方法與靜態(tài)方法
在JDK8之前捌木,Interface之中是可以定義變量和方法的,變量必須是public static final 的 嫉戚, 方法必須是public abstract的 刨裆, 由于這些修飾符是默認(rèn)的,所以在JDK8之前彬檀,下面寫(xiě)法是等價(jià)的
public interface JDK8BeforeInterface {
public static final int field1 = 0;
int field2 = 0;
public abstract void m1(int a) throws Exception ;
void m2(int a) throws Exception;
}
JDK8及以后崔拥,允許我們?cè)诮涌谥卸xstatic方法和default方法。
public interface JDK8Interface {
// static修飾符定義靜態(tài)方法
static void staticMethod() {
System.out.println("接口中定義靜態(tài)方法");
}
// default修飾符定義默認(rèn)方法
default void defaultMethod() {
System.out.println("接口中的默認(rèn)方法");
}
}
再定義一個(gè)接口的實(shí)現(xiàn)類(lèi):
public class JDK8InterfaceImpl implements JDK8Interface ,JDK8Interface1 {
//實(shí)現(xiàn)接口后凤覆,因?yàn)槟J(rèn)方法不是抽象方法链瓦,所以可以不重寫(xiě),但是如果開(kāi)發(fā)需要盯桦,也可以重寫(xiě)
}
靜態(tài)方法慈俯,只能通過(guò)接口名調(diào)用,不可以通過(guò)實(shí)現(xiàn)類(lèi)的類(lèi)名或者實(shí)現(xiàn)類(lèi)的對(duì)象調(diào)用拥峦。default方法贴膘,只能通過(guò)接口實(shí)現(xiàn)類(lèi)的對(duì)象來(lái)調(diào)用。
public class Main {
public static void main(String[] args) {
// static方法必須通過(guò)接口類(lèi)調(diào)用
JDK8Interface.staticMethod();
//default方法必須通過(guò)實(shí)現(xiàn)類(lèi)的對(duì)象調(diào)用
new JDK8InterfaceImpl().defaultMethod();
}
}
當(dāng)然如果接口中的默認(rèn)方法不能滿(mǎn)足某個(gè)實(shí)現(xiàn)類(lèi)需要略号,那么實(shí)現(xiàn)類(lèi)可以覆蓋默認(rèn)方法刑峡。
public class AnotherJDK8InterfaceImpl implements JDK8Interface {
@Override
public void defaultMethod() {
System.out.println("接口實(shí)現(xiàn)類(lèi)覆蓋了接口中的default");
}
}
五、最新的Date/Time API
新的時(shí)間及日期API位于java.time中玄柠,它們都是不可變且線(xiàn)程安全的
屬性 | 含義 |
---|---|
Instant | 代表的是時(shí)間戳 |
LocalDate | 代表日期突梦,比如2020-01-14 |
LocalTime | 代表時(shí)刻,比如12:59:59 |
LocalDateTime | 代表具體時(shí)間 2020-01-12 12:22:26 |
ZonedDateTime | 代表一個(gè)包含時(shí)區(qū)的完整的日期時(shí)間羽利,偏移量是以UTC/ 格林威治時(shí)間為基準(zhǔn)的 |
Period | 代表時(shí)間段 |
ZoneOffset | 代表時(shí)區(qū)偏移量宫患,比如:+8:00 |
Clock | 代表時(shí)鐘,比如獲取目前美國(guó)紐約的時(shí)間 |
1这弧、獲取當(dāng)前時(shí)間
Instant instant = Instant.now(); //獲取當(dāng)前時(shí)間戳
System.out.println("instant ==> " + instant);
//instant ==> 2020-02-01T12:09:28.772Z
LocalDate localDate = LocalDate.now(); //獲取當(dāng)前日期
System.out.println("localDate ==> " + localDate);
//localDate ==> 2020-02-01
LocalTime localTime = LocalTime.now(); //獲取當(dāng)前時(shí)刻
System.out.println("localTime ==> " + localTime);
//localTime ==> 20:09:28.914
LocalDateTime localDateTime = LocalDateTime.now(); //獲取當(dāng)前具體時(shí)間
System.out.println("localDateTime ==> " + localDateTime);
//localDateTime ==> 2020-02-01T20:09:28.914
ZonedDateTime zonedDateTime = ZonedDateTime.now(); //獲取帶有時(shí)區(qū)的時(shí)間
System.out.println("zonedDateTime ==> " + zonedDateTime);
//zonedDateTime ==> 2020-02-01T20:09:28.916+08:00[Asia/Shanghai]
2娃闲、字符串轉(zhuǎn)日期
String date = "2020-01-10";
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate localDate = LocalDate.parse(date, formatter1);
System.out.println("localDate ==> " + localDate);
3、日期轉(zhuǎn)字符串
Date dd = new Date();
LocalDateTime ldt = dd.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(ldt);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String format = ldt.format(dtf);
System.out.println(format);
4匾浪、Date轉(zhuǎn)換LocalDate
Date date = new Date();
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
// atZone()方法返回在指定時(shí)區(qū)從此Instant生成的ZonedDateTime皇帮。
LocalDate localDate = instant.atZone(zoneId).toLocalDate();
System.out.println("Date = " + date);
System.out.println("LocalDate = " + localDate);
5、LocalDate轉(zhuǎn)Date
ZoneId zoneId = ZoneId.systemDefault();
LocalDate localDate = LocalDate.now();
ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
Date date = Date.from(zdt.toInstant());
System.out.println("LocalDate = " + localDate);
System.out.println("Date = " + date);
6蛋辈、時(shí)間戳轉(zhuǎn)LocalDateTime
long timestamp = System.currentTimeMillis();
Instant instant = Instant.ofEpochMilli(timestamp);
LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
7属拾、LocalDateTime轉(zhuǎn)時(shí)間戳
LocalDateTime dateTime = LocalDateTime.now();
dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli();
dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
8、LocalDate方法總結(jié)
getYear() int 獲取當(dāng)前日期的年份
getMonth() Month 獲取當(dāng)前日期的月份對(duì)象
getMonthValue() int 獲取當(dāng)前日期是第幾月
getDayOfWeek() DayOfWeek 表示該對(duì)象表示的日期是星期幾
getDayOfMonth() int 表示該對(duì)象表示的日期是這個(gè)月第幾天
getDayOfYear() int 表示該對(duì)象表示的日期是今年第幾天
withYear(int year) LocalDate 修改當(dāng)前對(duì)象的年份
withMonth(int month) LocalDate 修改當(dāng)前對(duì)象的月份
withDayOfMonth(intdayOfMonth) LocalDate 修改當(dāng)前對(duì)象在當(dāng)月的日期
isLeapYear() boolean 是否是閏年
lengthOfMonth() int 這個(gè)月有多少天
lengthOfYear() int 該對(duì)象表示的年份有多少天(365或者366)
plusYears(longyearsToAdd) LocalDate 當(dāng)前對(duì)象增加指定的年份數(shù)
plusMonths(longmonthsToAdd) LocalDate 當(dāng)前對(duì)象增加指定的月份數(shù)
plusWeeks(longweeksToAdd) LocalDate 當(dāng)前對(duì)象增加指定的周數(shù)
plusDays(longdaysToAdd) LocalDate 當(dāng)前對(duì)象增加指定的天數(shù)
minusYears(longyearsToSubtract) LocalDate 當(dāng)前對(duì)象減去指定的年數(shù)
minusMonths(longmonthsToSubtract) LocalDate 當(dāng)前對(duì)象減去注定的月數(shù)
minusWeeks(longweeksToSubtract) LocalDate 當(dāng)前對(duì)象減去指定的周數(shù)
minusDays(longdaysToSubtract) LocalDate 當(dāng)前對(duì)象減去指定的天數(shù)
compareTo(ChronoLocalDateother) int 比較當(dāng)前對(duì)象和other對(duì)象在時(shí)間上的大小,返回值如果為正捌年,則當(dāng)前對(duì)象時(shí)間較晚,
isBefore(ChronoLocalDateother) boolean 比較當(dāng)前對(duì)象日期是否在other對(duì)象日期之前
isAfter(ChronoLocalDateother) boolean 比較當(dāng)前對(duì)象日期是否在other對(duì)象日期之后
isEqual(ChronoLocalDateother) boolean 比較兩個(gè)日期對(duì)象是否相等