一,lammda表达式的使用
函数式接口:就是一个接口中只有一个抽象方法,lammda表达式其实就是创建一个接口实例,并对这个抽象方法进行重写
java8内置四大核心函数式接口
java.util.function包下的接口都是“无意义”的,这个“无意义”并不是说它们没有存在的意义,而是说它们都必须放到具体的语境中去才会真正的意义。或者说,它们是“非典型”的Java API就体现在,它们自己是没有语境(Context)的,它们实际上可以说就是为Lambda表达式而存在的——你不需要了解它叫什么(匿名的),它们是作为参数在对象的方法的中传递的。
其实,所有java.util.function包下的接口的方法名,我们都不必关心,因为当我们用它们的时候,压根不会去显式地调用它们,方法名也是“无意义”的,它们只是方便大家去理解他的用途。但是,方法的参数和返回值是需要我们关心和注意的。
function包下总共有43个接口,可分为这四类核心函数式接口:Function、Supplier、Consumer、Predicate。
1.消费型接口
Consumer:消费型接口 单一抽象方法为:void accept(T t);
-
作用:消费某个对象**(传入一个泛型参数,不返回任何值)**
-
举例:forEach: Iterable接口的foeEach方法 需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代。
2.供给型接口
Supplier:供给型接口 T get();
- 作用:创建一个对象(工厂类)(不传入参数,返回一个值)
- 举例:Optional.orElseGet(Supplier<? extends T>):当this对象为null,就通过传入supplier创建一个T返回。(Optional类是一种容器对象,要么包装值,要么为空)
3.函数式接口
Function<T,R>:函数型接口 R apply(T t);
- 作用:实现一个“一元函数”,即传入一个值经过函数的计算返回另一个值。(传入一个参数,返回一个值)
4.断言型接口
Predicate:断言型接口 单一抽象方法: boolean test(T t);
作用:判断对象是否符合某个条件**(传入一个参数,返回一个布尔值)**
举例:主要用于流的筛选。给定一个包含若干项的流,Stream接口的filter方法传入一个Predicate并返回一个新的流,它仅包含满足给定谓词的项。
方法引用:
方法引用就是lammda表达式的简化版,就是说函数式接口中抽象方法已经有类去实现了,咱们就可以直接调用这个方法
主要有三种表现形式:
1)引用特定对象的实例方法:对象::实例方法名(object::instanceMethod)
(x)->System.out.println(x);
简化为:System.out::println
2)引用静态方法:类::静态方法名(Class::staticMethod)
()->Math.random();
简化为:Math::random
3)调用特定类型的任意对象的实例方法: 类::实例方法名(Class::instanceMethod ):这个比较特殊,可能接口中的抽象方法和引用方法格式不同,而是接口中的抽象方法的第一个参数如果可以调用这个方法,那么就可以通过这个方法的类名加实例方法去调用引用方法
x->x.length();
简化为:String::length
注意:如果通过类名引用一个传入多个参数的方法,则接口中的抽象方法的第一个参数将作为方法的调用者,其他元素作为方法的参数,可以使用ClassName::instanceMethod 。
(o1,o2)->o1.compareTo(o2);
简化为:String::compareTo
注意:需要实现的接口中的抽象方法的 参数列表与返回值类型 要与 当前调用的方法的参数列表、返回值类型保持一致
StreamApi的使用:检索集合或者数组
特点:1.与集合不同,集合是与内存打交道,而Stream Api是与cpu打交道
2.延迟执行,只有在需要结果的时候才会执行,或者执行了终止操作的时候才会执行
大概步骤就是:
1.获取stream实例对象
通过集合获取stream对象:集合实例.stream();
通过数组获取stream对象:Arrays.stream(数组实例)
通过Stream类下自带的of方法,of的参数就是任意元素
2.中间操作
(1)筛选与切片
filter(predicate p):对元素进行筛选
limit(n) :获取前n条数据
skip(n) : 跳过前n条数据,返回后边的数据
distinct():元素去重
(2)映射
map(Function f):对元素进行修改或者操作,返回一个新的stream实例
flatMap(Function f):与map的区别就是,在操作中返回的新的stream实例,里边的元素应该还是stream实例,如果是map的话就会stream里边嵌套stream,如果这flatmap,就会把里边的stream拆解,追加到外边的stream中
(3)排序
Sorted():可以是自然排序,如果元组本身就可以直接排序就可以使用自然排序
Sorted(Comparator<T> c):可以自己进行定制,如果是对象,要根据某个元素排序就需要用到定制排序,一下就是根据对象年龄参数进行升序排序
3.终止操作
allMatch(predicate p):检查是否匹配所有元素
anyMatch(predicate p)检查是否至少匹配一个元素
noneMatch(predicate p)检查是否没有匹配的元素
findFirst()返回第一个元素
findany()返回任意元素
count()返回元素总个数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c) 内部迭代
归约结束操作:
reduce(T 起始值,BinaryOperator),这里可以设置起始值,将流中的元素反复结合起来
eg:list.stream().reduce(0,Integer::Sum)
reduce(BinaryOperator) 不设置起始值,求元素的和
收集结束操作:
collect(Collector c)
eg:list.stream().collect(Collector.Toset)
list变换map的常用操作:
//以brand和price属性分别作为key和value创建map,若集合中存在key重复的元素,就取后一个
Map<String, BigDecimal> collect = cars.stream().collect(Collectors.toMap(Car::getBrand, Car::getPrice, (x, y) -> y));
//以brand为key,将集合分组,每个brand对应一个Car集合
Map<String, List<Car>> collect1 = cars.stream().collect(Collectors.groupingBy(Car::getBrand));
//将集合按是否满足partitioningBy中的断言函数为标准,分成两个集合
Map<Boolean, List<Car>> bn = cars.stream().collect(Collectors.partitioningBy(k -> "BMW".equals(k.getBrand())));
Collector中的常用方法:
/**
* 返回List集合
* toList
*/
@Test
public void stream1(){
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,6);
System.out.println(integers);
List<Integer> collect = integers.stream().map(x -> x * x).collect(Collectors.toList());
System.out.println(collect);
}
/**
* 返回Set集合
* toSet
*/
@Test
public void stream3(){
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,6);
System.out.println(integers);
Set<Integer> collect = integers.stream().filter(value -> value > 2).collect(Collectors.toSet());
System.out.println(collect);
}
/**
* counting
* 计算元素数量
*/
@Test
public void stream4(){
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,6);
System.out.println(integers);
Long collect = integers.stream().collect(Collectors.counting());
System.out.println(collect);
System.out.println(integers);
}
/**
* maxBy
* 取最大值【naturalOrder自然排序】
*/
@Test
public void stream5(){
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,6);
System.out.println(integers);
Integer integer = integers.stream().collect(Collectors.maxBy(Comparator.naturalOrder())).get();
System.out.println(integer);
System.out.println(integers);
}
/**
* minBy
* 取最小值【naturalOrder自然排序】
*/
@Test
public void stream6(){
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,6);
System.out.println(integers);
Integer integer = integers.stream().collect(Collectors.minBy(Comparator.naturalOrder())).get();
System.out.println(integer);
System.out.println(integers);
}
/**
* partitioningBy
* 用于将一个集合划分为2个集合并将其添加到映射中集合中,
* 满足给定条件的划分一个集合,并以true为key
* 不满足给定条件的划分一个集合,并以false为key
*/
@Test
public void stream7(){
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,6);
System.out.println(integers);
Map<Boolean, List<Integer>> collect = integers.stream().collect(Collectors.partitioningBy(v -> (int) v > 3));
System.out.println(collect);
System.out.println(integers);
}
/**
* joining
* 连用指定的字符串连接集合内的元素
* 结合内元素须为String类型
*/
@Test
public void stream8(){
List<String> integers = Arrays.asList("1","2");
String collect = integers.stream().collect(Collectors.joining(","));
System.out.println(collect);
//用指定的字符串连接集合内的元素,并在首尾加上指定字符
String collect2 = integers.stream().collect(Collectors.joining(",","《","》"));
System.out.println(collect2);
//用指定的字符串连接int类型集合内的元素
List<Integer> integers3 = Arrays.asList(1,1);
String collect3 = integers3.stream().map(a-> String.valueOf(a) ).collect(Collectors.joining(","));
System.out.println(collect3);
}
/**
* 集合的平均值
* averagingLong
* averagingInt
* averagingDouble
*/
@Test
public void stream9(){
//long类型求平均值
List<Long> longValues = Arrays.asList(100l,200l,300l);
Double d1 = longValues
.stream()
.collect(Collectors.averagingLong(x -> x * 2));
System.out.println("long类型求平均值:"+d1);
//int类型求平均值
List<Integer> intValues = Arrays.asList(12,30,45);
Double d2 = intValues
.stream()
.collect(Collectors.averagingInt(x->x));
System.out.println("int类型求平均值:"+d2);
//double类型求平均值
List<Double> doubleValues = Arrays.asList(1.1,2.0,3.0,4.0,5.0,5.0);
Double d3 = doubleValues
.stream()
.collect(Collectors.averagingDouble(x->x));
System.out.println("double类型求平均值:"+d3);
}
/**
* 求和
* summingLong
* summingInt
* summingDouble
*/
@Test
public void stream10(){
//long类型求平均值
List<Long> longValues = Arrays.asList(100l,200l,300l);
Long d1 = longValues
.stream()
.collect(Collectors.summingLong(x -> x));
System.out.println("long类型求和:"+d1);
//int类型求平均值
List<Integer> intValues = Arrays.asList(12,30,45);
Integer d2 = intValues
.stream()
.collect(Collectors.summingInt(x->x));
System.out.println("int类型求和:"+d2);
//double类型求平均值
List<Double> doubleValues = Arrays.asList(1.1,2.0,3.0,4.0,5.0,5.0);
Double d3 = doubleValues
.stream()
.collect(Collectors.summingDouble(x->x));
System.out.println("double类型求求和:"+d3);
}
/**
* 汇总整数
* 得到平均值、最小值、最大值、所有值的计数和总和。
*/
@Test
public void stream11(){
List<Integer> intValues = Arrays.asList(12,30,45);
IntSummaryStatistics collect = intValues
.stream()
.collect(Collectors.summarizingInt(x -> x));
System.out.println(collect);
}
/**
*
* 创建Map
* toMap
* Function.identity()指向集合中的值
*/
@Test
public void stream12(){
List<String> integers = Arrays.asList("dsf","sfsf");
Map<String, Integer> collect = integers.stream().collect(Collectors.toMap(item -> item, String::length));
System.out.println(collect);
Map<String, Integer> collect2 = integers.stream().collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(collect2);
//去重创建map【map中key唯一,不可重复】
List<String> strings = Arrays.asList("dsf","sfsf","ggfdd","sfsf");
Map<String, Integer> collect3 = strings.stream().collect(Collectors.toMap(item -> item, String::length,(i1,i2)->i1));
System.out.println(collect3);
}
/**
* 分组函数
* GroupingBy
*/
@Test
public void stream13(){
//分组
List<String> strings = Arrays.asList("alpha","beta","gamma");
final Map<Integer, List<String>> collect = strings.stream().collect(Collectors.groupingBy(String::length));
System.out.println(collect);
//分组求和
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> map = new HashMap<>();
map.put("name","张三");
map.put("money","25");
Map<String, String> map2 = new HashMap<>();
map2.put("name","张四");
map2.put("money","50");
Map<String, String> map3 = new HashMap<>();
map3.put("name","张三");
map3.put("money","30");
list.add(map);
list.add(map2);
list.add(map3);
Map<String, Integer> name = list.stream().collect(Collectors.groupingBy(item -> item.get("name"), Collectors.summingInt(item -> Integer.parseInt(item.get("money")))));
System.out.println(name);
}
}
三,Optional类的使用
可以防止空指针的发生
获取optional类实例的三种方式:
Optional.of(T f):创建一个Optional实例,t必须为空
Optional.empty():创建一个空的Optional实例
Optional.ofNullable(T t):t可以为null
optional类实例方法的使用:
orElse(T t):调用者如果为空就使用参数中的实例
eg:Optional<Boy> o=Optional.ofNullable(new Boy());
Boy b= o.orElse(new BOY);//假如o为null,就使用后边的对象为boy赋值