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 c = (x) -> System.out.println(x);
//Consumer c = x -> System.out.println(x);
c.accept("666");
语法格式3:有多个参数,有返回值,多条语句;小括号,大括号都不能省略
Comparator t = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
语法格式4:若lambda体中只有一条语句时,return ,大括号都可以不写
参数列表数据类型可以不写,jvm 编译器可以上下文推断出数据类型,又称“类型推断”
Comparator t = (x,y) ->Integer.compare(x,y);
口诀:左右遇一括号省 左侧推断类型省 能省就省
二、Lambda 表达式 需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionInterface 修饰,它可以检测是不是函数式接口
练习:
///1
List 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 {
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 mf) {
System.out.println(mf.getValue(l1, l2));
}
@FunctionalInterface
public interface TestLambda {
public boolean test(T t);
}
2.1java 内置四大核心函数式接口
Consumer 消费型接口 void accept(T t);
// 方式1
Consumer cs = new Consumer() {
@Override
public void accept(String t) {
// TODO Auto-generated method stub
System.out.println(t);
}
};
cs.accept("aaaaaaaaaaa");
// Lambda方式2
Consumer cs1 = (x)-> System.out.println(x);
cs1.accept("6666666666");
Supplier 供给型接口 T get();
//Supplier 供给型接口 T get();
@Test
public void test4() {
List num = getNumList(10, () ->(int)(Math.random()*100));
System.out.println(num);
}
///需求 产生指定个数的整数,存放到集合中
public List getNumList(int num,Supplier sup){
List list = new ArrayList();
for(int i = 0;i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
Function 函数型接口 R apply(T t);
//Function 函数型接口 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,Functionf) {
return f.apply(str);
}
Predicate 断言型接口 boolean test(T t);
// Predicate 断言型接口 boolean test(T t);
@Test
public void test6() {
List s = Arrays.asList("aa","hh","fhkaf","很好的");
List strList = optString(s,x->x.length()>2);
System.out.println(strList);
}
/// 将满足条件的字符串放到集合中
public List optString(List list,Predicatepre){
List strList = new ArrayList<>();
for (String s : list) {
if(pre.test(s)) {
strList.add(s);
}
}
return strList;
}
常用的其他函数式接口:
BiFuntion
UnaryOperatot
BinaryOperator
BiConsumer
三、 3.1方法引用
方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda 表达式的另一种表现形式)
主要有三种语法格式:
对象:: 实例方法名
类ishil :: 静态方法名
类 :: 实例方法名
注意:1. lambda 体中调用方法的参数列表与返回值类型,要与函数式接口这种抽象方法的函数列表与返回值一致
如果lambda 参数列表第一个是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName:: method 如:
BiPredicate bp = (x,y) -> x.equals(y); BiPredicate bp2 = String::equals;
// 对象
@Test
public void test7() {
PrintStream ps = System.out;
Consumer con = x -> ps.println(x);
con.accept("aaa");
// 简化 左右类型要一致
Consumer con2 =System.out::println;
con2.accept("6666");
}
@Test
public void test8() {
Emloyee e = new Emloyee();
Supplier sup = e::getName;
String name = sup.get();
System.out.println(name);
}
// 类--静态方法
@Test
public void test9() {
Comparator com = Integer::compareTo;
int c = com.compare(22, 11);
System.out.println(c); // 1
}
// 类--实例方法
@Test
public void test91() {
BiPredicate bp = (x,y) -> x.equals(y);
BiPredicate bp2 = String::equals;
System.out.println(bp.test("11","aa"));
}
2.3 构造器引用
ClassName::new
注意;需要调用的构造器参数列表要与函数值接口中参数列表一致;
@Test
public void test2() {
Supplier sup = () -> new Employee();
// 构造器引用
Supplier 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 fun = (x) -> new String[x];
String[] strs = fun.apply(4);
System.out.println(strs.length); //4
Function 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 list = new ArrayList<>();
Stream stream = list.stream();
// 2. 通过Arrays 中的静态方法stram() 获取数组流
Employee[] emps = new Employee[5];
Stream stream2 = Arrays.stream(emps);
// 3. 通过Stream类中的静态方法of()
Stream stream3 = Stream.of("aa","bb","cc");
// 4. 创建无限流(迭代、生成)
//迭代
Stream 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 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 stream = list.stream()
.filter(e -> {
System.out.println("Stream 中间操作");
return e.getAge() > 36;
});
// 惰性求值
stream.forEach(System.out::println);
}
// 外部迭代
@Test
public void test2() {
Iterator 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 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 = list.stream()
.map(LambdaStream::filterCharacter); //[a,b,c,[d,e]] 相当于集合中add()方法
stream.forEach(sm -> sm.forEach(System.out::println));
System.out.println("-----------------");
// 方式2
Stream 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 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 max = employee.stream()
.max((e1,e2) -> Integer.compare(e1.getSalary(),e1.getSalary()));
System.out.println(max.get());
Optional 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 op = employee.stream()
.sorted((e1,e2) -> -Integer.compare(e1.getSalary(), e2.getSalary()))
.findFirst(); // 有可能空指针 所以 java8 封装到Optional 中
System.out.println(op.get());
Optional 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 list = employee.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("------------------------");
Set set = employee.stream()
.map(Employee::getStatus)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("------------------------");
HashSet 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 op = employee.stream()
.collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op.get());
// 最小值
Optional op2 = employee.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Integer::compare));
System.out.println(op2.get());
}
// 多级分组
@Test
public void test6() {
Map>> 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> 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 = 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> 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>> 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> 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 list = employee.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("------------------------");
Set set = employee.stream()
.map(Employee::getStatus)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("------------------------");
HashSet 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 op = employee.stream()
.collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op.get());
// 最小值
Optional op2 = employee.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Integer::compare));
System.out.println(op2.get());
}
/应用场景
1.用 Comparator 来排序
2.用 Runnable 执行代码块
3.GUI 事件处理
未完待续.....
共同进步,共同学习