學習代碼
1.主要內容
1.Lambda運算式
2. 函式式介面
3. 方法參考于構造器參考
4. Stream API
5. 介面中的默認方法與靜態方法
6. 新時間日期API
7. 重復注解
入門案例:根據條件獲取員工資訊
//員工表
public class Employee {
private String name;
private int age;
private double salary;
....
}
//員工資訊
List<Employee> emplpyees = Arrays.asList(
new Employee("張三", 14, 5444.42),
new Employee("李四", 39, 3434.15),
new Employee("王五", 31, 5425.55),
new Employee("趙六", 11, 2544.42),
new Employee("陳七", 98, 944.42));
1.傳統方式
@Test
public void test3() {
List<Employee> emps = filterEmployees(emplpyees);
System.out.println(emps);
}
// 獲取當前員工中年齡大于35的員工
public List<Employee> filterEmployees(List<Employee> list) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : list) {
if (emp.getAge() >= 35) {
emps.add(emp);
}
}
return emps;
}
如果條件改變呢?比如,改成想要工資大于5000的員工資訊.傳統方式,拷貝代碼,修改if代碼
優化方式一:設計模式,策略設計模式
定義一個借口,根據條件創建實作類
//定義一個介面
public interface MyProdicate<T> {
public boolean test(T t);
}
//實作類,
public class FilterEmployeeByAge implements MyProdicate<Employee>{
@Override
public boolean test(Employee t) {
return t.getAge()>=35;
}
}
//判斷
public List<Employee> filterEmployees(List<Employee> list, MyProdicate<Employee> mp) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : list) {
if (mp.test(emp)) {
emps.add(emp);
}
}
return emps;
}
//測驗
@Test
public void test4() {
List<Employee> emps = filterEmployees(emplpyees, new FilterEmployeeByAge());
System.out.println(emps);
}
不過,這種方式中,每加一個條件,就要加一個實作類,不好,在此基礎上進行優化
匿名內部類
// 優化方式二,匿名內部類
public void test5() {
List<Employee> emps = filterEmployees(emplpyees, new MyProdicate<Employee>() {
@Override
public boolean test(Employee t) {
return t.getSalary() >= 5000;
}
});
System.out.println(emps);
}
匿名內部類每次使用,還是要寫多余代碼,可以繼續優化
lambda運算式
// 優化方式三:lambda]
@Test
public void test6() {
List<Employee> emps = filterEmployees(emplpyees, (e) -> e.getSalary() < 5000);
emps.forEach(System.out::println);
}
如果沒有介面.怎么優化Stream API
// 優化方式四,只有emplpyees,Stream API
@Test
public void test7() {
emplpyees.stream().filter((e) -> e.getSalary() < 5000).forEach(System.out::println);
}
2.Lambda運算式
1.匿名函式
Lambda是一個匿名函式,可以理解為一段可以傳遞的代碼(將代碼像資料一樣傳遞);
可以寫出更簡潔、更靈活的代碼;
作為一種更緊湊的代碼風格,是Java語言表達能力得到提升,
2.語法格式
1.lambda運算式的基礎語法
java8中引入新的運算子"->",箭頭運算子/lambda運算子 箭頭運算子將lambda 運算式拆分成兩部分:
左側:lambda的引數串列 右側:lambda中所需要執行的功能,即lambda體
? 語法格式1:無引數,無回傳值 :()->具體功能
? 語法格式2:有一個引數,無回傳值:(x)->具體功能
? 語法格式3:若只有一個引數,引數小括號可以省略不寫:x->具體功能
? 語法格式4:有兩個以上的引數,lambda體中有多條陳述句,有回傳值:
? 語法格式5:有兩個引數,lambda體只有一條陳述句,有回傳值,{}和return可以省略
? 語法格式6:lambda運算式的資料型別可以省略不寫,因為jvm的編譯器可以通過背景關系推斷出資料型別,即型別推斷
口訣:
? 左右遇一括號省
? 左側推斷型別省
package cn.zj.lambda;
import java.util.Comparator;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
/**
* 1.lambda運算式的基礎語法,java8中引入新的運算子"->",箭頭運算子/lambda運算子 箭頭運算子將lambda 運算式拆分成兩部分:
* 左側:lambda的引數串列 右側:lambda中所需要執行的功能,即lambda體
*
* 語法格式1:無引數,無回傳值 :()->具體功能
* 語法格式2:有一個引數,無回傳值:(x)->具體功能
* 語法格式3:若只有一個引數,引數小括號可以省略不寫:x->具體功能
* 語法格式4:有兩個以上的引數,lambda體中有多條陳述句,有回傳值:
* 語法格式5:有兩個引數,lambda體只有一條陳述句,有回傳值,{}和return可以省略
* 語法格式6:lambda運算式的資料型別可以省略不寫,因為jvm的編譯器可以通過背景關系推斷出資料型別,即型別推斷
*
* 口訣:
* 左右遇一括號省
* 左側推斷型別省
*
*/
public class TestLambda2 {
// 1.無引數,無回傳值
@Test
public void test1() {
int i = 1;// 在7之前,內部類呼叫同級別變數引數,需要加final修飾符,8以后不加,底層默認加了
Runnable r = () -> System.out.println("hello Lambda" + i);
r.run();
}
@Test
public void test2() {
Consumer<String> c=(x)->System.out.println(x);
c.accept("lambda");
}
@Test
public void test3() {
Consumer<String> c=x->System.out.println(x);
c.accept("lambda");
}
@Test
public void test4() {
Comparator<Integer> com=(x,y)->{
System.out.println("lambda多條陳述句");
return Integer.compare(x, y);
};
int compare = com.compare(11, 33);
System.out.println(compare);
}
@Test
public void test5() {
Comparator<Integer> com=(x,y)->Integer.compare(x, y);
int compare = com.compare(11, 33);
System.out.println(compare);
}
}
2.lambda運算式需要函式式介面的支持函式式介面
函式式介面:只有一個抽象方法的介面
public interface MyProdicate<T> {
public boolean test(T t);
}
可以使用注解@FunctionalInterface修飾,檢查是否是函式式介面
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
3.練習
3.1.呼叫Collections.sort()方法,通過定制排序比較兩個Employee(先按年齡比,年齡相同按姓名比),使用lambda作為引數傳遞
@Test
public void test1() {
Collections.sort(emps, (e1, e2) -> {
if (e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
return Integer.compare(e1.getAge(), e2.getAge());
}
});
emps.forEach(System.out::println);
}
3.2.①宣告函式式介面,介面中宣告抽象方法,public String getValue(String str);
②宣告類LambdaTest,類中撰寫方法使用介面作為引數,將一個字串轉為大寫并回傳
③再將字串的第2和第4個索引位置進行截取
@FunctionalInterface
public interface MyFunction {
public String getValue(String str);
}
@Test
public void test2() {
String str = strHandler("hellolambda", (s) -> s.toUpperCase());
str = strHandler(str, (s) -> s.substring(2, 5));
System.out.println(str);
}
public String strHandler(String str, MyFunction mf) {
return mf.getValue(str);
}
3.3.①宣告一個帶兩個泛型的函式式介面,泛型型別為<T,R>,T為引數,R為回傳值,
②介面中宣告對應方法
③在LambdaTest類中宣告方法,使用介面作為引數,計算兩個long型引數的和
④再計算兩個long型引數的乘積
@FunctionalInterface
public interface MyFunction2<T,R> {
public R getValue(T t1,T t2);
}
@Test
public void test3() {
Long l1=longHandler(4121754L,55524L,(x,y)->x+y);
Long l2=longHandler(4121754L,55524L,(x,y)->x*y);
System.out.println(l1);
System.out.println(l2);
}
public Long longHandler(Long l1, long l2, MyFunction2<Long,Long> mf) {
return mf.getValue(l1, l2);
}
3.java內置四大型別介面
| 函式式介面 | 引數型別 | 回傳型別 | 用途 |
|---|---|---|---|
| Consumer 消費型介面 | T | void | 對型別為T的物件應用操作:void accept(T t) |
| Supplier 提供型介面 | 無 | T | 回傳型別為T的物件:T get() |
| Function<T, R> 函式型介面 | T | R | 對型別為T的物件應用操作,并回傳結果為R型別的物件:R apply(T t) |
| Predicate 斷言型介面 | T | boolean | 確定型別為T的物件是否滿足某約束,并回傳boolean值:boolean test(T t) |
1.Consumer 消費型介面
//消費型介面Consumer
@Test
public void test1() {
happy(10000,(m)->System.out.println("吃消費"+m));
}
public void happy(double money,Consumer<Double> con) {
con.accept(money);
}
2.Suppplier供給型介面 T get()
//供給型介面Supplier
@Test
public void test2() {
List<Integer> list=getNumList(10,()->(int)(Math.random()*100));
System.out.println(list);
}
//產生一些整數,并放入集合中
public List<Integer> getNumList(int num,Supplier<Integer> sup){
List<Integer> list=new ArrayList<>();
for(int i=0;i<num;i++) {
list.add(sup.get());
}
return list;
}
3.Function<T,R>函式型介面 R apply(T t)
//函式型介面Function
@Test
public void test3() {
String str = strHandler(" 韓梅梅要嫁給王五了 ", (s)->s.trim());
System.out.println(str);
}
//處理字串
public String strHandler(String str,Function<String,String> fun) {
return fun.apply(str);
}
4.Predicate斷定型介面
// 斷定型介面Predicate
@Test
public void test4() {
List<String> list = Arrays.asList("hello","world","lambda","ok","good");
List<String> strList = filterStr(list, (s)->s.length()>4);
System.out.println(strList);
}
// 將滿足條件的字串加到集合中
public List<String> filterStr(List<String> list, Predicate<String> pre) {
List<String> strList = new ArrayList<>();
for (String str : list) {
if (pre.test(str))
strList.add(str);
}
return strList;
}
其它介面

3.方法參考與構造器參考
1.方法參考
如果lambda體中的內容已經有方法實作了,可以使用"方法參考"(可以理解為lambda的另一種表現形式)
1.物件::實體方法名
//物件::實體方法名
@Test
public void test1() {
Consumer<String> con=(x)->System.out.println(x);
con.accept("哇咔咔");
//方法參考:介面中抽象方法的引數和回傳值型別,需要與要參考的方法的引數和回傳值型別一樣
PrintStream ps=System.out;
Consumer<String> con1=ps::println;
con1.accept("把金三角");
Consumer<String> con2=System.out::println;
con2.accept("asasa");
}
@Test
public void test2() {
Employee emp=new Employee("張三", 11, 124.55);
Supplier<String> sup=()->emp.getName();
String str = sup.get();
System.out.println(str);
//方法參考
Supplier<Integer> sup1=emp::getAge;
Integer age = sup1.get();
System.out.println(age);
}
2.類::靜態方法名
//類::靜態方法
@Test
public void test3() {
Comparator<Integer> com=(x,y)->Integer.compare(x, y);
Comparator<Integer> com1=Integer::compare;
int compare = com1.compare(11, 12);
System.out.println(compare);
}
3.類::實體方法名
//類::實體方法名
@Test
public void test4() {
BiPredicate<String, String>bp=(x,y)->x.equals(y);
//注意,第一個引數是實體方法的呼叫者,第二個引數是實體方法的引數
BiPredicate<String, String>bp1=String::equals;
boolean test = bp1.test("ss", "ss");
System.out.println(test);
}
4.注意
注意:
lambda體中呼叫方法的引數串列與回傳值型別,要與函式式介面中抽象方法的引數串列和回傳值型別保持一致lambda引數串列中的第一個引數是實體方法的引數者,第二個引數是實體方法的引數時可以使用類::實體方法名
2.構造器參考
格式:ClassName::new
//無參
@Test
public void test1() {
Supplier<Employee> sup=()->new Employee();
//構造器參考,無參
Supplier<Employee> sup1=Employee::new;
}
//有引數
@Test
public void test2() {
Function<Integer, Employee>fun=(x)->new Employee(x);
Function<Integer, Employee>fun1=Employee::new;
Employee emp = fun1.apply(11);
System.out.println(emp);
//兩個引數
BiFunction<Integer,Integer, Employee>bf=Employee::new;
Employee emp2 = bf.apply(11,21);
System.out.println(emp2);
}
注意:需要呼叫的構造器的引數串列要與函式式介面中抽象方法的引數串列保持一致
3.陣列參考
Type::new
@Test
public void test1() {
Function<Integer, String[]> fun=(x)->new String[x];
String[] strArr = fun.apply(12);
System.out.println(strArr.length);
Function<Integer, String[]> fun1=String[]::new;
String[] strArr2 = fun1.apply(10);
System.out.println(strArr2.length);
}
4.Stream API
1.Stream 概念
是資料渠道,用于操作資料源(集合.陣列等)所生成的元素序列. “集合將的事資料,流講的是計算” 注意:
ⅰ. Stream自己不會存盤元素
ⅱ. Stream不會改變源物件.相反,他們會回傳一個持有結果的新Stream
ⅲ. Stream操作是延遲執行的.這意味著他們會等到需要結果的時候才執行
2.操作步驟
1.創建 Stream
一個資料源(集合,陣列等)獲取一個流
- 通過Collection系列集合提供的stream()或paralleStream()
- 通過Arrays中的靜態方法stream()獲取陣列流
- 通過Stream類中的靜態方法of()
- 創建無限流
// 創建Stream
@Test
public void test1() {
// 1.通過Collection系列集合提供的stream()或paralleStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//2.通過Arrays中的靜態方法stream()獲取陣列流
Employee[] emps=new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
//3.通過Stream類中的靜態方法of()
Stream<String> stream3 = Stream.of("aa","bb","cc");
//4.創建無限流
//1)迭代
Stream<Integer> stream4 = Stream.iterate(0, (x)->x+2);
//stream4.limit(10).forEach(System.out::println);
//2)生成
Stream<Double> stream5 = Stream.generate(()->Math.random());
//limit(10)中間操作
//forEach 終止操作
stream5.limit(10).forEach(System.out::println);//終止操作
}
2.中間操作
一個中間操作鏈,對資料源的資料進行處理
多個中間操作可以連接起來形成一個流水線,除非流水線上出發終止操作,否則中間操作不會執行任何的處理.而在終止操作時一次性全部處理,稱為"惰性求值"
1.篩選與切片
| 方法 | 描述 |
|---|---|
| filter(Predicate p) | 接收Lambda,從流中排除某些元素 |
| distinct() | 篩選,通過流所生成元素的hashCode()和equals()去除重復元素 |
| limit(long maxSize) | 截斷流,使其元素不超過給定數量 |
| skip(long n) | 跳過元素,回傳一個扔掉了前n個元素的流.若流中元素不足n個,則回傳一個空流.與limit(n)互補 |
public class TestStreamAPI02 {
List<Employee> emps = Arrays.asList(
new Employee("張三", 14, 5444.42),
new Employee("李四", 39, 3434.15),
new Employee("李四", 39, 3434.15),
new Employee("王五", 31, 5425.55),
new Employee("趙六", 31, 2544.42),
new Employee("陳七", 98, 944.42));
//中間操作
/*
* 篩選與切片
* filter-接受lambda,從流中排除某些元素
* limit-截斷流,使其元素不能超過給定數量
* skip(n) -跳過元素,回傳一個扔掉了前n個元素的流,若流中元素不足n個,則回傳一個空流.與limit(n)互補
* distinct-篩選,通過流所生成元素的hashCode()和equals()去除重復元素
*
*/
//distinct
@Test
public void test5() {
emps.stream().filter((e)->e.getSalary()>3000).distinct().forEach(System.out::println);
}
//skip
@Test
public void test4() {
emps.stream().filter((e)->e.getSalary()>5000).skip(1).forEach(System.out::println);
}
//limit,得到對應的資料后,會停止迭代,短路
@Test
public void test3() {
emps.stream().filter((e)->e.getSalary()>5000).limit(2).forEach(System.out::println);
}
//內部迭代:迭代操作由Stream API完成
//filter
@Test
public void test1() {
//中間操作,不會執行任何操作
Stream<Employee> stream = emps.stream().filter((e)->e.getAge()>35);
//終止操作,一次性執行全部內容,"惰性求值"
stream.forEach(System.out::println);
}
//外部迭代
@Test
public void test2() {
Iterator<Employee> it = emps.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
2.映射
? map:接收 Lambda ,將元素轉換為其他形式或提取資訊;接受一個函式作為引數,該函式會被應用到每個元素上,并將其映射成一個新的元素
? flatMap:接收一個函式作為引數,將流中每一個值都換成另一個流,然后把所有流重新連接成一個流
public class TestStreamAPI3 {
List<Employee> emps = Arrays.asList(
new Employee("張三", 14, 5444.42),
new Employee("李四", 39, 3434.15),
new Employee("李四", 39, 3434.15),
new Employee("王五", 31, 5425.55),
new Employee("趙六", 31, 2544.42),
new Employee("陳七", 98, 944.42));
//中間操作
//映射
//map-接收Lambda,將元素轉換成其它形式或提取資訊,接收一個函式作為引數,該函式會被應用到每個元素上,并將其映射成一個新的元素
//flatMap-接收一個函式作為引數,將流中的每個值都換成另一個流,然后把所有流連接成一個流
//flatMap
@Test
public void test2() {
List<String> list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream().flatMap(TestStreamAPI3::filterCharacter).forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (char c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
//map
@Test
public void test1() {
List<String> list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream().map((x)->x.toUpperCase()).forEach(System.out::println);
System.out.println("-------------------------------");
emps.stream().map((x)->x.getName()).forEach(System.out::println);
System.out.println("-------------------------------");
Stream<Stream<Character>> stream=list.stream().map(TestStreamAPI3::filterCharacter);
stream.forEach((sm)->{
sm.forEach(System.out::println);
});
}
}
3.排序
? sorted():自然排序
? sorted(Comparator c):定制排序
//中間操作
//排序
//sorted():自然排序
//sorted(Comparator c):定制排序
//sorted(Comparator c)
@Test
public void test2() {
emps.stream().sorted((x,y)->{
if(x.getAge()==y.getAge()) {
return x.getName().compareTo(y.getName());
}else {
return Integer.compare(x.getAge(), y.getAge());
}
}).forEach(System.out::println);
}
//sorted
@Test
public void test1() {
List<String> list=Arrays.asList("aaa","ddd","bbb","eee","ccc");
list.stream().sorted().forEach(System.out::println);
}
3.終止操作(終端操作)
一個終止操作,執行中間操作鏈,并產生結果
1.查找與匹配
? allMatch:檢查是否匹配所有元素
? anyMatch:檢查是否至少匹配一個元素
? noneMatch:檢查是否沒有匹配所有元素
? findFirst:回傳第一個元素
? findAny:回傳當前流中的任意元素
? count:回傳流中元素的總個數
? max:回傳流中最大值
? min:回傳流中最小值
public class TestStreamAPI4 {
List<Employee> emps = Arrays.asList(
new Employee(1,"張三", 14, 5444.42,Status.FREE),
new Employee(2,"李四", 39, 3434.15,Status.BUSY),
new Employee(3,"李四", 39, 3434.15,Status.VOCATION),
new Employee(4,"王五", 31, 5425.55,Status.FREE),
new Employee(5,"趙六", 31, 2544.42,Status.BUSY),
new Employee(6,"陳七", 98, 944.42,Status.BUSY));
// 終止操作
// 查找與匹配
// allMatch:檢查是否匹配所有元素
// anyMatch:檢查是否至少匹配一個元素
// noneMatch:檢查是否沒有匹配所有元素
// findFirst:回傳第一個元素
// findAny:回傳當前流中的任意元素
// count:回傳流中元素的總個數
// max:回傳流中最大值
// min:回傳流中最小值
//min
@Test
public void test8() {
/*
* Optional<Employee> op =
* emps.stream().min((x,y)->Double.compare(x.getSalary(), y.getSalary()));
* System.out.println(op.get().getSalary());
*/
Optional<Double> op = emps.stream().map(Employee::getSalary).min(Double::compare);
System.out.println(op.get());
}
//max
@Test
public void test7() {
Optional<Employee> op = emps.stream().max((x,y)->Double.compare(x.getSalary(), y.getSalary()));
System.out.println(op.get());
}
//count
@Test
public void test6() {
long count = emps.stream().count();
System.out.println(count);
}
//findAny
@Test
public void test5() {
Optional<Employee> op = emps.stream().filter((e)->e.getStatus().equals(Status.FREE)).findAny();
System.out.println(op.get());
}
//findFirst
@Test
public void test4() {
Optional<Employee> op = emps.stream().sorted((x,y)->Double.compare(x.getSalary(), y.getSalary())).findFirst();
//op.orElse(null)
System.out.println(op.get());
}
//noneMatch
@Test
public void test3() {
boolean b1 = emps.stream().noneMatch((e)->e.getStatus().equals(Status.BUSY));
System.out.println(b1);
}
//anyMatch
@Test
public void test2() {
boolean b1 = emps.stream().anyMatch((e)->e.getStatus().equals(Status.BUSY));
System.out.println(b1);
}
//allMatch
@Test
public void test1() {
boolean b1 = emps.stream().allMatch((e)->e.getStatus().equals(Status.BUSY));
System.out.println(b1);
}
}
2.規約與收集
!
? 歸約:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以將流中的資料反復結合起來,得到一個值,通常和map合用,map-reduce模式
? 收集:collect 將流轉換成其他形式;接收一個 Collector 介面的實作,用于給流中元素做匯總的方法
public class TestStreamAPI6 {
List<Employee> emps = Arrays.asList(new Employee(1, "張三", 14, 5444.42, Status.FREE),
new Employee(2, "李四", 39, 3434.15, Status.BUSY), new Employee(3, "李四", 39, 3434.15, Status.VOCATION),
new Employee(4, "王五", 31, 5425.55, Status.FREE), new Employee(5, "趙六", 31, 2544.42, Status.BUSY),
new Employee(6, "陳七", 98, 944.42, Status.BUSY));
// 終止操作
// 收集:collect 將流轉換成其他形式;接收一個 Collector 介面的實作,用于給流中元素做匯總的方法
//連接
@Test
public void test9() {
String string = emps.stream().map(Employee::getName).collect(Collectors.joining(","));
System.out.println(string);
}
@Test
public void test8() {
DoubleSummaryStatistics collect = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(collect);
}
// 磁區/分片
@Test
public void test7() {
Map<Boolean, List<Employee>> map = emps.stream().collect(Collectors.partitioningBy((e) -> e.getAge() > 30));
System.out.println(map);
}
// 多級分組
@Test
public void test6() {
// 按狀態分組
Map<Status, Map<Object, List<Employee>>> map = emps.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() > 30) {
return "青年";
} else {
return "老家伙";
}
})));
System.out.println(map);
}
// 分組
@Test
public void test5() {
// 按狀態分組
Map<Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
@Test
public void test4() {
// 總數
Long collect = emps.stream().collect(Collectors.counting());
System.out.println("總數:" + collect);
// 工資平均值
Double averag = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println("工資平均值:" + averag);
// 工資總和
Double sumSalary = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println("工資總和:" + sumSalary);
// 工資最大值
Optional<Employee> op = emps.stream()
.collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
System.out.println("最大工資:" + op.get());
// 工資最小值
Optional<Double> op2 = emps.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));
System.out.println("最小工資:" + op2.get());
}
@Test
public void test3() {
// 收集所有的員工姓名
// list中
List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
System.out.println(list);
System.out.println("--------");
// set中
Set<String> set = emps.stream().map(Employee::getName).collect(Collectors.toSet());
System.out.println(set);
System.out.println("--------");
// 其它集合中
HashSet<String> hashSet = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
}
// 歸約:reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
// 可以將流中的資料反復結合起來,得到一個值
@Test
public void test2() {
// 計算工資總和
Optional<Double> op = emps.stream().map((e) -> e.getSalary()).reduce(Double::sum);
System.out.println(op.get());
}
@Test
public void test1() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(sum);
}
}
5.并行流與串行流
!
? 并行流:就是把一個內容分成幾個資料塊,并用不同的執行緒分別處理每個資料塊的流
? Java 8 中將并行進行了優化,我們可以很容易的對資料進行操作;Stream API 可以宣告性地通過 parallel() 與 sequential() 在并行流與串行流之間切換
fork/join
public class ForkJoinCalculate extends RecursiveTask<Long>{
private static final long serialVersionUID = 1L;
private long start;
private long end;
private static final long THRESHPLD =1000;
/**
* @param start
* @param end
*/
public ForkJoinCalculate(long start, long end) {
super();
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length=end-start;
if(length<=THRESHPLD) {
long sum=0;
for(long i=start;i<=end;i++) {
sum+=i;
}
return sum;
}else {
long middle = (start + end) / 2;
ForkJoinCalculate left=new ForkJoinCalculate(start, middle);
left.fork();//拆分成子任務,同時加入執行緒佇列
ForkJoinCalculate right=new ForkJoinCalculate(middle+1, end);
right.fork();
return left.join()+right.join();
}
}
}
//fork/join 數值越大,越能體現性能
@Test
public void test1() {
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task=new ForkJoinCalculate(0, 100000000);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗費時間:"+Duration.between(start, end).toMillis()+"毫秒");//70
}
//普通for回圈
@Test
public void test2() {
Instant start = Instant.now();
long sum=0;
for(int i=0;i<=100000000;i++) {
sum+=i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗費時間:"+Duration.between(start, end).toMillis()+"毫秒");//30
}
java8并行流 parallel 底層 fork/join
//java8并行流 parallel()
@Test
public void test3(){
Instant start = Instant.now();
OptionalLong op = LongStream.rangeClosed(0, 1000000000L)
.parallel()
.reduce(Long::sum);
System.out.println(op.getAsLong());
Instant end = Instant.now();
System.out.println("耗費時間:"+Duration.between(start, end).toMillis()+"毫秒");//49->257毫秒
}
6.Optional
定義:Optional 類 (java.util.Optional) 是一個容器類,代表一個值存在或不存在,原來用 null
表示一個值不存在,現在用 Optional 可以更好的表達這個概念;并且可以避免空指標例外
常用方法:
? Optional.of(T t):創建一個 Optional 實體
? Optional.empty(T t):創建一個空的 Optional 實體
? Optional.ofNullable(T t):若 t 不為 null,創建 Optional 實體,否則空實體
? isPresent():判斷是否包含某值
? orElse(T t):如果呼叫物件包含值,回傳該值,否則回傳 t
? orElseGet(Supplier s):如果呼叫物件包含值,回傳該值,否則回傳 s 獲取的值
? map(Function f):如果有值對其處理,并回傳處理后的 Optional,否則回傳 Optional.empty()
? flatmap(Function mapper):與 map 相似,要求回傳值必須是 Optional
public class TestOptiona {
/*
* Optional.of(T t):創建一個 Optional 實體
* Optional.empty(T t):創建一個空的 Optional 實體
* Optional.ofNullable(T t):若 t 不為 null,創建 Optional 實體,否則空實體
* isPresent():判斷是否包含某值
* orElse(T t):如果呼叫物件包含值,回傳該值,否則回傳 t
* orElseGet(Supplier s):如果呼叫物件包含值,回傳該值,否則回傳 s 獲取的值
* map(Function f):如果有值對其處理,并回傳處理后的 Optional,否則回傳Optional.empty()
* flatmap(Function mapper):與 map 相似,要求回傳值必須是 Optional
*
*/
@Test
public void test8() {
Optional<Employee> op = Optional.ofNullable(new Employee(1, "張三", 110, 55440.14, Status.BUSY));
Optional<String> flatMap = op.flatMap((e)->Optional.of(e.getName()));
System.out.println(flatMap.get());
}
@Test
public void test7() {
Optional<Employee> op = Optional.ofNullable(new Employee(1, "張三", 110, 55440.14, Status.BUSY));
Optional<String> map = op.map((e)->e.getName());
System.out.println(map.get());
}
@Test
public void test6() {
Optional<Employee> op = Optional.ofNullable(new Employee());
Employee emp=op.orElseGet(()-> new Employee(1, "張三", 110, 55440.14, Status.BUSY));
System.out.println(emp);
}
@Test
public void test5() {
Optional<Employee> op = Optional.ofNullable(new Employee());
Employee emp=op.orElse(new Employee(1, "張三", 110, 55440.14, Status.BUSY));//避免空指標例外
System.out.println(emp);
}
@Test
public void test4() {
//ofNullable是empty和of的綜合
Optional<Employee> op = Optional.ofNullable(new Employee());
if(op.isPresent()) {
Employee emp = op.get();//空指標報錯位置
System.out.println(emp);
}
}
@Test
public void test3() {
//ofNullable是empty和of的綜合
Optional<Employee> op = Optional.ofNullable(new Employee());
Employee emp = op.get();//空指標報錯位置
System.out.println(emp);
}
@Test
public void test2() {
Optional<Employee> op = Optional.empty();
Employee emp = op.get();//空指標報錯位置
System.out.println(emp);
}
@Test
public void test1() {
Optional<Employee> op = Optional.of(new Employee());//傳入null空指標報錯位置
Employee emp = op.get();
System.out.println(emp);
}
}
7.介面中的默認方法與靜態方法
1.默認方法
public interface MyFun {
default String getName() {
return "libo";
}
default Integer getAge() {
return 22;
}
}
public class MyClass {
public String getName() {
return "MyClass類";
}
}
public class SubClass extends MyClass implements MyFun{
}
public static void main(String[] args) {
SubClass sc=new SubClass();
String name = sc.getName();//類優先原則
System.out.println(name);
}
public interface MyInterfaces {
default String getName() {
return "MyInterfaces介面";
}
}
public class SubClass2 implements MyFun,MyInterfaces{
//實作多介面,并有同方法,必須實作該方法
@Override
public String getName() {
return MyFun.super.getName();
}
}
2.靜態方法
public interface MyInterfaces {
default String getName() {
return "MyInterfaces介面";
}
public static void show() {
System.out.println("介面中的靜態方法");
}
}
MyInterfaces.show();
8.新時間API
1.傳統時間存在安全問題
public static void main(String[] args) throws Exception {
//存在執行緒安全問題
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = () -> sdf.parse("20210111");
ExecutorService pool = Executors.newFixedThreadPool(10);
ArrayList<Future<Date>> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(pool.submit(task));
}
for (Future<Date> future : result) {
System.out.println(future.get());
}
pool.shutdown();
}
//執行緒安全
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> df = ThreadLocal
.withInitial(() -> new SimpleDateFormat("yyyyMMdd"));
public static Date convert(String source) throws ParseException {
return df.get().parse(source);
}
}
public static void main(String[] args) throws Exception {
//存在執行緒安全問題
//SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
//Callable<Date> task = () -> sdf.parse("20210111");
Callable<Date> task =() ->DateFormatThreadLocal.convert("20181212");
ExecutorService pool = Executors.newFixedThreadPool(10);
ArrayList<Future<Date>> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(pool.submit(task));
}
for (Future<Date> future : result) {
System.out.println(future.get());
}
pool.shutdown();
}
public static void main(String[] args) throws Exception {
//java8新時間
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task =() ->LocalDate.parse("20181212",dtf);
ExecutorService pool = Executors.newFixedThreadPool(10);
ArrayList<Future<LocalDate>> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(pool.submit(task));
}
for (Future<LocalDate> future : result) {
System.out.println(future.get());
}
pool.shutdown();
}
2.本地時間

常用方法:
| 方法名 | 回傳值型別 | 解釋 |
|---|---|---|
| now( ) | static LocalDateTime | 從默認時區的系統時鐘獲取當前日期 |
| of(int year, int month, int dayOfMonth, int hour, int minute, int second) | static LocalDateTime | 從年,月,日,小時,分鐘和秒獲得 LocalDateTime的實體,將納秒設定為零 |
| plus(long amountToAdd, TemporalUnit unit) | LocalDateTime | 回傳此日期時間的副本,并添加指定的數量 |
| get(TemporalField field) | int | 從此日期時間獲取指定欄位的值為 int |
public class TestLocalDateTime {
//1.LocalDate LocalTime LocalDateTime
@Test
public void test1() {
//獲取當前時間日期 now
LocalDateTime ldt=LocalDateTime.now();
System.out.println(ldt);
//指定時間日期 of
LocalDateTime ldt2 = LocalDateTime.of(2021, 8, 14, 16, 24, 33);
System.out.println(ldt2);
//加 plus
LocalDateTime ldt3 = ldt2.plusYears(2);
System.out.println("加兩年:"+ldt3);
//減 minus
LocalDateTime ldt4 = ldt2.minusMonths(3);
System.out.println("減三個月:"+ldt4);
//獲取指定的你年月日時分秒... get
System.out.println("年"+ldt2.getDayOfYear());
System.out.println("時"+ldt2.getHour());
System.out.println("秒"+ldt2.getSecond());
}
}
3.時間戳
Instant:以 Unix 元年 1970-01-01 00:00:00 到某個時間之間的毫秒值
// 時間戳
// Instant:以 Unix 元年 1970-01-01 00:00:00 到某個時間之間的毫秒值
@Test
public void test2() {
// 默認獲取 UTC 時區 (UTC:世界協調時間)0時區時間
Instant ins1 = Instant.now();
System.out.println(ins1);
// 帶偏移量的時間日期 (如:UTC + 8)
OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);
//轉換成對應的毫秒值
long milli = ins1.toEpochMilli();
System.out.println(milli);
//構建時間戳
Instant ins2 = Instant.ofEpochSecond(6000);
System.out.println(ins2);//1970-01-01T01:40:00Z
}
4.時間/日期之間的間隔
? Duration:計算兩個時間之間的間隔
? Period:計算兩個日期之間的間隔
//Duration:計算兩個時間之間的間隔
// Period:計算兩個日期之間的間隔
//Duration:計算兩個時間之間的間隔
@Test
public void test3() {
Instant ins1 = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1, ins2);
System.out.println(duration.toMillis());
}
// Period:計算兩個日期之間的間隔
@Test
public void test4() {
LocalDate ld1 = LocalDate.of(2019, 11, 11);
LocalDate ld2 = LocalDate.now();
Period period = Period.between(ld1, ld2);
System.out.println(period.getDays());
}
5.時間校正器

// TemporalAdjusters 時間校正器
@Test
public void test1() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
//指定日期時間中的 年 月 日 ...
LocalDateTime ldt2 = ldt.withDayOfMonth(10);//將月中的時間制定成10
System.out.println(ldt2);
//指定時間校正器
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println(ldt3);
//自定義時間校正器:下一個作業日是什么時候
LocalDateTime ldt4=ldt.with((l)->{
LocalDateTime ldt0 =(LocalDateTime) l;
DayOfWeek dow = ldt0.getDayOfWeek();
if (dow.equals(DayOfWeek.FRIDAY)) {
return ldt0.plusDays(3);
} else if (dow.equals(DayOfWeek.SATURDAY)) {
return ldt0.plusDays(2);
} else {
return ldt0.plusDays(1);
}
});
System.out.println(ldt4);
}
6.時間格式化
DateTimeFormatter:格式化時間 / 日期
//DateTimeFormatter:格式化時間 / 日期
@Test
public void test1() {
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime ldt = LocalDateTime.now();
System.out.println(dtf.format(ldt));
//自定義格式化 ofPattern
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String d2 = dtf2.format(ldt);
System.out.println(d2);
//決議
LocalDateTime ldt2 = ldt.parse(d2,dtf2);
System.out.println(ldt2);
}

7.時區的處理
? ZonedDate
? ZonedTime
? ZonedDateTime
// 時區的處理
// ZonedDate
// ZonedTime
// ZonedDateTime
@Test
public void test1() {
//查看支持的時區
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
//指定時區
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Chile/Continental"));
System.out.println(ldt1);
//帶時區
ZonedDateTime zdt1 = ldt1.atZone(ZoneId.of("Chile/Continental"));
System.out.println(zdt1);
}
9.重復注解與注解型別
//容器類
@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 })
@Retention(RetentionPolicy.RUNTIME) // 宣告周期
public @interface MyAnnotation {
String value() default "Java 8";
}
//重復注解
@Test
@MyAnnotation("Hello")
@MyAnnotation("World")
public void test01() throws NoSuchMethodException {
Class<TestAnnotation> clazz = TestAnnotation.class;
Method test01 = clazz.getMethod("test01");
MyAnnotation[] mas = test01.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation ma : mas) {
System.out.println(ma.value());
}
}
Java 8 新增注解:新增ElementType.TYPE_USE
和ElementType.TYPE_PARAMETER(在Target上)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/282913.html
標籤:java
