JAVA8 新特性主要內容部分:
-
1.Lambda 表達式
-
2.函數式接口
-
3.方法引用與構造器引用
-
4.Stream API
-
5.接口中的默認方法與靜態方法
-
6.新時間日期API
-
7.其他新特性
1.速度快、代碼少、強大的stream 、便於並行、最大化減少空指針
2.哈希算法 hashmap 數組-鏈表-紅黑樹 加載因子0.75
3.ConcurrentHashMap CAS算法 16
4.方法區 換成 MetaSpace 元空間 默認用物理內存 也可配置
取消永久區
# 第一部分 Lambda 表達式
lambda: 匿名函數、可傳遞的代碼鏈式編程
Lambda表達式的基礎語法:java8中引入了一個新的操作符 “->” 箭頭操作符將lambda表達式分爲兩部分:
1.左側:參數列表 (接口中對應的抽象方法參數 函數式接口只有一個抽象方法)
2.右側:表達式中所需執行的功能,即lambda體
語法格式1:無餐,無返回值
Runnable r2 = () -> System.out.println("執行了");
語法格式2:有一個參數,且無返回值;小括號可以不寫
Consumer<String> c = (x) -> System.out.println(x);
//Consumer<String> c = x -> System.out.println(x);
c.accept("666");
語法格式3:有多個參數,有返回值,多條語句;小括號,大括號都不能省略
Comparator<Integer> t = (x,y) -> {
System.out.println("函數式接口");
return Integer.compare(x,y);
};
語法格式4:若lambda體中只有一條語句時,return ,大括號都可以不寫
參數列表數據類型可以不寫,jvm 編譯器可以上下文推斷出數據類型,又稱“類型推斷”
Comparator<Integer> t = (x,y) ->Integer.compare(x,y);
口訣:左右遇一括號省 左側推斷類型省 能省就省
二、Lambda 表達式 需要“函數式接口”的支持
函數式接口:接口中只有一個抽象方法的接口,稱爲函數式接口。可以使用註解@FunctionInterface 修飾,它可以檢測是不是函數式接口
練習:
///1
List<Emloyee> emps = Arrays.asList(
new Emloyee(11,"zhangsan","6666"),
new Emloyee(22,"李四","4444"),
new Emloyee(55,"李四5","54444"),
new Emloyee(33,"王五","55555555"),
new Emloyee(33,"王五2","2222555"),
new Emloyee(44,"zhaoliu","34125")
);
@Test
public void test() {
Collections.sort(emps,(e,e2)->
e.getAge()==e2.getAge() ?
e.getName().compareTo(e2.getName()) :
Integer.compare(e.getAge(),e2.getAge())
);
for (Emloyee e : emps) {
System.out.println(e);
}
}
///2
public interface StringOpt {
public String opt(String opt);
}
// 字符串處理
@Test
public void test2() {
String s = strHandler("\t\t sfda dfdf ", x -> x.trim() );
System.out.println(s);
String s2 = strHandler("abcde", x-> x.substring(2));
System.out.println(s2);
}
public String strHandler(String str,StringOpt so) {
return so.opt(str);
}
public interface MyFunction<T,R> {
public R getValue(T t1,T t2);
}
// 對於兩個Long 型數據處理
@Test
public void test3() {
op(100L,200L,(x,y) -> x + y);
op(100L,200L,(x,y) -> x * y);
}
public void op(Long l1,Long l2,MyFunction<Long,Long> mf) {
System.out.println(mf.getValue(l1, l2));
}
@FunctionalInterface
public interface TestLambda<T> {
public boolean test(T t);
}
2.1java 內置四大核心函數式接口
Consumer<T> 消費型接口 void accept(T t);
// 方式1
Consumer<String> cs = new Consumer<String>() {
@Override
public void accept(String t) {
// TODO Auto-generated method stub
System.out.println(t);
}
};
cs.accept("aaaaaaaaaaa");
// Lambda方式2
Consumer<String> cs1 = (x)-> System.out.println(x);
cs1.accept("6666666666");
Supplier<T> 供給型接口 T get();
//Supplier<T> 供給型接口 T get();
@Test
public void test4() {
List<Integer> num = getNumList(10, () ->(int)(Math.random()*100));
System.out.println(num);
}
///需求 產生指定個數的整數,存放到集合中
public List<Integer> getNumList(int num,Supplier<Integer> sup){
List<Integer> list = new ArrayList<Integer>();
for(int i = 0;i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
Function<T,R> 函數型接口 R apply(T t);
//Function<T,R> 函數型接口 R apply(T t);
@Test
public void test5() {
String i = strHandler1("sssabfjd/t113", x -> x.substring(0, 1));
System.out.println(i);
}
//需求處理字符串
public String strHandler1(String str,Function<String, String>f) {
return f.apply(str);
}
Predicate<T> 斷言型接口 boolean test(T t);
// Predicate<T> 斷言型接口 boolean test(T t);
@Test
public void test6() {
List<String> s = Arrays.asList("aa","hh","fhkaf","很好的");
List<String> strList = optString(s,x->x.length()>2);
System.out.println(strList);
}
/// 將滿足條件的字符串放到集合中
public List<String> optString(List<String> list,Predicate<String>pre){
List<String> strList = new ArrayList<>();
for (String s : list) {
if(pre.test(s)) {
strList.add(s);
}
}
return strList;
}
常用的其他函數式接口:
BiFuntion<T,U,R> R apply(T t,U u);
UnaryOperatot<T> T apply(T t); 它是Function 的子接口
BinaryOperator<T> void accept(T t1,T t2 ); 是BiFunction 的子接口
BiConsumer<T,U> void accept(T t,U u);
三、 3.1方法引用
方法引用:若Lambda體中的內容有方法已經實現了,我們可以使用“方法引用”(可以理解爲方法引用是Lambda 表達式的另一種表現形式)
主要有三種語法格式:
對象:: 實例方法名
類ishil :: 靜態方法名
類 :: 實例方法名
注意:1. lambda 體中調用方法的參數列表與返回值類型,要與函數式接口這種抽象方法的函數列表與返回值一致
-
如果lambda 參數列表第一個是實例方法的調用者,而第二個參數是實例方法的參數時,可以使用 ClassName:: method 如:
BiPredicate<String, String> bp = (x,y) -> x.equals(y); BiPredicate<String, String> bp2 = String::equals;
// 對象
@Test
public void test7() {
PrintStream ps = System.out;
Consumer<String> con = x -> ps.println(x);
con.accept("aaa");
// 簡化 左右類型要一致
Consumer<String> con2 =System.out::println;
con2.accept("6666");
}
@Test
public void test8() {
Emloyee e = new Emloyee();
Supplier<String> sup = e::getName;
String name = sup.get();
System.out.println(name);
}
// 類--靜態方法
@Test
public void test9() {
Comparator<Integer> com = Integer::compareTo;
int c = com.compare(22, 11);
System.out.println(c); // 1
}
// 類--實例方法
@Test
public void test91() {
BiPredicate<String, String> bp = (x,y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp.test("11","aa"));
}
2.3 構造器引用
ClassName::new
注意;需要調用的構造器參數列表要與函數值接口中參數列表一致;
@Test
public void test2() {
Supplier<Employee> sup = () -> new Employee();
// 構造器引用
Supplier<Employee> sup2 = Employee::new;
Employee e = sup2.get();
System.out.println(e); //Employee [id=0, age=0, name=null, salary=null]
}
3.2 數組引用
Type::new;
// 數組引用
@Test
public void test3() {
Function<Integer,String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(4);
System.out.println(strs.length); //4
Function<Integer,String[]> fun2 = String[]::new;
String[] str2 = fun2.apply(6);
System.out.println(str2.length);//6
}
四 Stream API 流
問題:什麼是流Sream?
是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列。“集合講的是數據,流講的是計算。”
① Stream 自己不會存儲元素。
② Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
③ Stream 是延遲執行的。 這就意味這他們會等到需要的結果時才執行。
三步走:
1.創建stream
// 1. 可以通過 Collection系列集合框架 提供 xxx.stream() 或者parallelStream()
// 2. 通過Arrays 中的靜態方法stram() 獲取數組流
// 3. 通過Stream類中的靜態方法of()
// 4. 創建無限流(迭代、生成)
/*
* 創建流對象
*/
// 1. 可以通過 Collection系列集合框架 提供 xxx.stream() 或者parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
// 2. 通過Arrays 中的靜態方法stram() 獲取數組流
Employee[] emps = new Employee[5];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通過Stream類中的靜態方法of()
Stream<String> stream3 = Stream.of("aa","bb","cc");
// 4. 創建無限流(迭代、生成)
//迭代
Stream<Integer> stream4 = Stream.iterate(0, x-> x+2);
stream4.limit(4).forEach(System.out::println);
//生成
Stream.generate(()->Math.random())
.limit(4)
.forEach(System.out::println);
2.中間操作(多箇中間操作可以連接起來形成一個流水線,只有流水線上有觸發終止操作的情況,否則中間操作不會執行任何的處理,終止操作時會一次性全部處理,也稱“惰性求值”)
常用的一些中間操作:
篩選與切片
filter---接收 Lambda,從流中排除某些元素
limit---截斷流,使其元素不超過某個指定數量
skip(n) --- 跳過元素,返回一個扔掉前n 個元素的流 ,若元素不足n 個,則返回一個空流,與limit(n)互補
distinct--- 篩選,通過流所生成元素的hashCode() 和 equals() 去除重複元素
映射
map--接收Lambda ,將元素轉換成其他形式或提取信息。接收一個函數作爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素。
flatMap--接收一個函數作爲參數,將該中的每一個值都換成另一個流,然後把所有流連接成一個流
排序
sorted() -- 自然排序(Comparable)
sorted(Comparator com) -- 自定義排序(Comparator)
// filter
// 添加公司員工
List<Employee> list = Arrays.asList(
new Employee("zhangsan", 33, 8888),
new Employee("zhangsan2", 35, 18888),
new Employee("zhangsan3", 37, 28888),
new Employee("zhangsan4", 43, 34888),
new Employee("zhangsan5", 53, 88888)
);
// 屬於內部迭代 由Stream API 完成
@Test
public void test() {
//中間操作,不會執行
Stream<Employee> stream = list.stream()
.filter(e -> {
System.out.println("Stream 中間操作");
return e.getAge() > 36;
});
// 惰性求值
stream.forEach(System.out::println);
}
// 外部迭代
@Test
public void test2() {
Iterator<Employee> it = list.iterator();
while(it.hasNext()) {
Employee e = it.next();
if(e.getAge() > 36) {
System.out.println(e);
}
}
}
// limit
@Test
public void test3() {
list.stream()
.filter(e -> {
System.out.println("短路"); //&& ||
return e.getAge() > 36;
})
.limit(2)
.forEach(System.out::println);
}
//skip
@Test
public void test4() {
list.stream()
.filter(e -> e.getSalary() > 5000)
.skip(2)
.forEach(System.out::println);
}
// distinct 通過流所生成元素的hashCode() 和 equals() 去除重複元素
@Test
public void test4() {
list.stream()
.filter(e -> e.getSalary() > 5000)
.skip(2)
.distinct()
.forEach(System.out::println);
}
// map
@Test
public void test5() {
List<String> list = Arrays.asList("aa","bb","cc","ddd");
list.stream()
.map(str-> str.toUpperCase())
.forEach(System.out::println);
System.out.println("-----------------");
employee.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
////
AA
BB
CC
DDD
-----------------
zhangsan
zhangsan2
zhangsan3
zhangsan4
zhangsan6
zhangsan5
zhangsan5
// flatMap
// 方式1
Stream<Stream<Character>> stream = list.stream()
.map(LambdaStream::filterCharacter); //[a,b,c,[d,e]] 相當於集合中add()方法
stream.forEach(sm -> sm.forEach(System.out::println));
System.out.println("-----------------");
// 方式2
Stream<Character> stream2 = list.stream()
.flatMap(LambdaStream::filterCharacter); //[a,b,c,d,e] 相當於集合中addAll()方法
stream2.forEach(System.out::println);
// sorted
/*
* 排序
* sorted() -- 自然排序(Comparable)
* sorted(Comparator com) -- 自定義排序(Comparator)
*/
@Test
public void test6() {
List<String> list = Arrays.asList("aa","dd","bb","1");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("--------------------------");
employee.stream()
.sorted((e1,e2) ->{
if(e1.getAge().equals(e2.getAge()))
return e1.getName().compareTo(e2.getName());
else
return e1.getAge().compareTo(e2.getAge());
}).forEach(System.out::println);
}
//////////
1
aa
bb
dd
--------------------------
Employee [name=zhangsan, age=33, salary=8888]
Employee [name=zhangsan2, age=35, salary=18888]
Employee [name=zhangsan3, age=37, salary=28888]
Employee [name=zhangsan4, age=43, salary=34888]
Employee [name=zhangsan5, age=53, salary=88888]
Employee [name=zhangsan5, age=53, salary=88888]
Employee [name=zhangsan6, age=53, salary=88888]
3.終止操作 (可以像sql 一樣 優雅編程 )
查找與匹配
* allMatch -- 檢查是否匹配所有元素
* anyMatch -- 檢查是否至少匹配一個元素
* noneMatch -- 檢查是否沒有匹配所有元素
* findFrist -- 返回第一個元素
* findAny -- 返回當前流中的任意元素
* count -- 返回流中元素總個數
* max -- 返回流中最大值
* min -- 返回流中最小值
歸約
* reduce(T identity,BinaryOpertor) / reduce(BinaryOperator) -- 可以將流中元素反覆結合起來,得到一個值
"map- reduce" 模式 兩個結合使用
收集
collect -- 將流轉換爲其他流。接收一個Collector 接口的實現,用於給Stream 中元素做彙總的方法
提取信息聚合 求最大值、最小值、和... ;
分組、多級分組、彙總統計、提取信息 連接成字符串
/*
* 查找與匹配
* allMatch -- 檢查是否匹配所有元素
* anyMatch -- 檢查是否至少匹配一個元素
* noneMatch -- 檢查是否沒有匹配所有元素
* findFrist -- 返回第一個元素
* findAny -- 返回當前流中的任意元素
* count -- 返回流中元素總個數
* max -- 返回流中最大值
* min -- 返回流中最小值
*/
@Test
public void test2() {
long count = employee.stream().count();
System.out.println(count);
Optional<Employee> max = employee.stream()
.max((e1,e2) -> Integer.compare(e1.getSalary(),e1.getSalary()));
System.out.println(max.get());
Optional<Integer> min = employee.stream()
.map(Employee::getSalary)
.min(Integer::compare);
System.out.println(min.get());
}
@Test
public void test1() {
boolean b1 = employee.stream()
.allMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(b1); // false
boolean b2 = employee.stream()
.anyMatch((e) -> e.getStatus().equals(Status.FREE));
System.out.println(b2); // true
boolean b3 = employee.stream()
.noneMatch((e) -> e.getStatus().equals(Status.VOCATION));
System.out.println(b3); // false
Optional<Employee> op = employee.stream()
.sorted((e1,e2) -> -Integer.compare(e1.getSalary(), e2.getSalary()))
.findFirst(); // 有可能空指針 所以 java8 封裝到Optional 中
System.out.println(op.get());
Optional<Employee> op2 = employee.parallelStream() // stream() 依次執行 parallelStream 並行同時執行
.filter(e -> e.getStatus().equals(Status.FREE)) // parallelStream 由於並行 所以結果不唯一 隨機
.findAny();
System.out.println(op2.get());
}
collect -- 將流轉換爲其他流。接收一個Collector 接口的實現,用於給Stream 中元素做彙總的方法
/*
* 收集
* collect -- 將流轉換爲其他流。接收一個Collector 接口的實現,用於給Stream 中元素做彙總的方法
*/
@Test
public void test4() {
List<String> list = employee.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("------------------------");
Set<Status> set = employee.stream()
.map(Employee::getStatus)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("------------------------");
HashSet<Status> hashset = employee.stream()
.map(Employee::getStatus)
.collect(Collectors.toCollection(HashSet::new));
System.out.println(hashset); //[BUSY, VOCATION, FREE]
System.out.println("------------------------");
// 總數
Long count = employee.stream()
.collect(Collectors.counting());
System.out.println(count); // 7
// 平均值
Double avg = employee.stream()
.collect(Collectors.averagingInt(Employee::getSalary));
System.out.println(avg);
// 最大值
Optional<Employee> op = employee.stream()
.collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op.get());
// 最小值
Optional<Integer> op2 = employee.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Integer::compare));
System.out.println(op2.get());
}
// 多級分組
@Test
public void test6() {
Map<Status, Map<String, List<Employee>>> map = employee.stream()
.collect(Collectors.groupingBy(Employee::getStatus,
Collectors.groupingBy(e -> {
if(e.getAge() <=35) return "青年";
else if (e.getAge() <=50 ) return "中年";
else return "老年";
})));
System.out.println(map);
//{VOCATION={中年=[Employee [name=zhangsan3, age=37, salary=28888, status=VOCATION]]}, FREE={青年=[Employee [name=zhangsan, age=33, salary=8888, status=FREE]], 中年=[Employee [name=zhangsan4, age=43, salary=34888, status=FREE]]}, BUSY={青年=[Employee [name=zhangsan2, age=35, salary=18888, status=BUSY]]}}
}
// 分組
@Test
public void test5() {
Map<Status, List<Employee>> map = employee.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
//{BUSY=[Employee [name=zhangsan2, age=35, salary=18888, status=BUSY]], FREE=[Employee [name=zhangsan, age=33, salary=8888, status=FREE], Employee [name=zhangsan4, age=43, salary=34888, status=FREE]], VOCATION=[Employee [name=zhangsan3, age=37, salary=28888, status=VOCATION]]}
}
// 添加公司員工
List<Employee> employee = Arrays.asList(
new Employee("zhangsan", 33, 8888,Status.FREE),
new Employee("zhangsan2", 35, 18888,Status.BUSY),
new Employee("zhangsan3", 37, 28888,Status.VOCATION),
new Employee("zhangsan4", 43, 34888,Status.FREE)
);
/*
* 收集
* collect -- 將流轉換爲其他流。接收一個Collector 接口的實現,用於給Stream 中元素做彙總的方法
*/
// 提取信息 連接成字符串
@Test
public void test9() {
String c = employee.stream()
.map(Employee::getName)
.collect(Collectors.joining(",",">>>","<<<"));
System.out.println(c);
}
//彙總 統計
@Test
public void test8() {
IntSummaryStatistics collect = employee.stream()
.collect(Collectors.summarizingInt(Employee::getSalary));
System.out.println(collect.getAverage());
System.out.println(collect.getMax());
}
// 分區
@Test
public void test7() {
Map<Boolean, List<Employee>> map = employee.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 10000));
System.out.println(map);//{false=[Employee [name=zhangsan, age=33, salary=8888, status=FREE]], true=[Employee [name=zhangsan2, age=35, salary=18888, status=BUSY], Employee [name=zhangsan3, age=37, salary=28888, status=VOCATION], Employee [name=zhangsan4, age=43, salary=34888, status=FREE]]}
}
// 多級分組
@Test
public void test6() {
Map<Status, Map<String, List<Employee>>> map = employee.stream()
.collect(Collectors.groupingBy(Employee::getStatus,
Collectors.groupingBy(e -> {
if(e.getAge() <=35) return "青年";
else if (e.getAge() <=50 ) return "中年";
else return "老年";
})));
System.out.println(map);
//{VOCATION={中年=[Employee [name=zhangsan3, age=37, salary=28888, status=VOCATION]]}, FREE={青年=[Employee [name=zhangsan, age=33, salary=8888, status=FREE]], 中年=[Employee [name=zhangsan4, age=43, salary=34888, status=FREE]]}, BUSY={青年=[Employee [name=zhangsan2, age=35, salary=18888, status=BUSY]]}}
}
// 分組
@Test
public void test5() {
Map<Status, List<Employee>> map = employee.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
//{BUSY=[Employee [name=zhangsan2, age=35, salary=18888, status=BUSY]], FREE=[Employee [name=zhangsan, age=33, salary=8888, status=FREE], Employee [name=zhangsan4, age=43, salary=34888, status=FREE]], VOCATION=[Employee [name=zhangsan3, age=37, salary=28888, status=VOCATION]]}
}
@Test
public void test4() {
List<String> list = employee.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("------------------------");
Set<Status> set = employee.stream()
.map(Employee::getStatus)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("------------------------");
HashSet<Status> hashset = employee.stream()
.map(Employee::getStatus)
.collect(Collectors.toCollection(HashSet::new));
System.out.println(hashset); //[BUSY, VOCATION, FREE]
System.out.println("------------------------");
// 總數
Long count = employee.stream()
.collect(Collectors.counting());
System.out.println(count); // 7
// 平均值
Double avg = employee.stream()
.collect(Collectors.averagingInt(Employee::getSalary));
System.out.println(avg);
// 最大值
Optional<Employee> op = employee.stream()
.collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op.get());
// 最小值
Optional<Integer> op2 = employee.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Integer::compare));
System.out.println(op2.get());
}
/////////////////應用場景
1.用 Comparator 來排序
2.用 Runnable 執行代碼塊
3.GUI 事件處理
未完待續.....
共同進步,共同學習