Lambda
特性:
允许把函数作为参数传递进方法。
前置条件:
必须是函数式接口----------》【函数式接口:满足以下三条1、接口中只有一个抽象方法。2、可以有默认实现的方法。3、可以有Object的方法】
@FunctionalInterface //注解可以没有,有可以在不符合函数式接口的情况下报编译错误
public interface DoSomeThing {
void doAny(String name);
}
//将函数式接口作为参数
static void ToSB(DoSomeThing doSomeThing) {
doSomeThing.doAny("狗子");
}
java内置函数式接口
Consumer<T> //消费型接口【有去无回】
void accept(T t);
Supplier<T> //供给型接口
T get();
Function<T,R> //函数型接口
R apply(T t);
Predicate<T> //断言型接口
boolean test(T t);
参数的传递:
()->{}
参数可以省略类型
参数只有一个可以省略()
//单个参数可以不加()
ToSB(name -> String.format("name:%s",name));
//类型可以省略,但有多个值时有类型必须都要有不能有的有有的没有
ToSB(String name->String.format("name:%s",name));
//代码块时必须有return,单行时则可以没有
ToSB2(name->{
String name1= name;
return "name:" + name1;
});
方法引用
静态方法引用:【注:Lambda体中调用的方法的参数列表与返回值类型与函数式接口中抽象方法的参数列表和返回值类型保持一致】
public static void main(String[] args) {
//非静态方法引用
ToSB(new TestLambda()::say);
//静态方法引用
ToSB(TestLambda::sayHi);
}
//非静态方法:new 类::方法名
String say(String name) {
return "hello" + name;
}
//静态方法:直接 类::方法名
static String sayHi(String name) {
return "hi" + name;
}
构造器引用
ClassName::new
【注:引用的构造器有参无参或者是那几个参与需要调用的构造器参数列表对应的函数式接口中抽象方法的参数列表保持一致】
数组引用
Type::new
Stream
特性:
Stream不存数据!
Stream不更改数据!
Stream为一次性的,不能重复使用!
每加一个“.”之前的流会报废,产生一个新的流!
创建List流的方法:
//1、通过Collection集合提供的串行流:stream()或并行流:parallelStream()
List<User> list = new ArrayList<>();
list.add(new User("张一",2,"red"));
list.add(new User("张二", 3, "yellow"));
list.add(new User("张三",4,"red"));
list.stream();
//2、通过Arrays中的静态方法stream()数组获取流
Arrays.stream(new User []{new User("张一",2,"red"),
new User("张二",3,"yellow"),
new User("张三",4,"red")});
//3、通过Stream中的静态方法of()获取流
Stream.of(new User("张一",2,"red"),
new User("张二", 3, "yellow")
,new User("张三",4,"red"));
//4、创建无限流----迭代
Stream<Integer> stream = Stream.iterate(0,x->x+2);
//5、创建无限流----生成
Stream.generate(()->Math.radom())
Stream流分为中间节点或者终止节点,区分方式:返回为Stream的为中间节点否则为终节点,不执行终止操作只有中间操作不会其任何效果。
流的执行顺序:
数据源执行时不是整个进入而是数据源中个个体一个个进入。
//list数据见上
list.stream().peek(a-> System.out.println(a.getName()))
.peek(a-> System.out.println(a.getCole()))
.toArray();
//*************控制台输出**********************
/**张一
*red
*张二
*yellow
*张三
*red
*/
Stream API
1、筛选与切片
操作 | 作用 |
---|---|
filter | 接收Lambda从流中排除某些元素 |
limit(n) | 截断流使其元素不超过给定数量n |
skip(n) | 跳过元素返回一个去掉了前n个元素的流,若流中元素不足n个则返回空流,与limit互补 |
distinct | 筛选,通过流所生成的元素的hashCode()和equals()去除重复 |
//操作通用数据
List<User> list = Arrays.asList(
new User("张一", 2, "大红脸"),
new User("张二", 3, "正宗黄种人"),
new User("张三", 4, "大红脸"),
new User("张四", 5, "黝黑透亮?黑无常:包大神"),
new User("张四", 6, "毫无血色?白无常:小白"));
//1、filter过滤年龄小于五的User
list.stream()
.filter(u -> u.getAge() < 5)
.forEach(System.out::println);
//*******************控制台*********************
// User(name=张一, age=2, cole=大红脸)
// User(name=张二, age=3, cole=正宗黄种人)
// User(name=张三, age=4, cole=大红脸)
//2、limit获取1条
list.stream()
.limit(1)
.forEach(System.out::println);
//*******************控制台*********************
//User(name=张一, age=2, cole=大红脸)
//3、skip去掉前2条取后面的
list.stream()
.skip(2)
.forEach(System.out::println);
//*******************控制台*********************
//User(name=张三, age=4, cole=大红脸)
//User(name=张四, age=5, cole=黝黑透亮?黑无常:包大神)
//User(name=张四, age=6, cole=毫无血色?白无常:小白)
//4、distinct去重,
list.stream()
.map(u->u.getCole()) //只取肤色
.distinct()
.forEach(System.out::println);
//*******************控制台*********************
//大红脸
//正宗黄种人
//黝黑透亮?黑无常:包大神
//毫无血色?白无常:小白
//【注】当去重的为对象,需要重写hashCode和equal
// List<User> list = Arrays.asList(
// new User("张一", 2, "大红脸"),
// new User("张二", 3, "正宗黄种人"),
// new User("张三", 4, "大红脸"),
// new User("张四", 5, "黝黑透亮?黑无常:包大神"),
// new User("张四", 5, "黝黑透亮?黑无常:包大神"),
// new User("张四", 5, "黝黑透亮?黑无常:包大神"),
// new User("张四", 6, "毫无血色?白无常:小白"));
// @Test
// public void Test1() {
// list.stream().distinct().forEach(System.out::println);
// }
//*******************控制台*********************
//User(name=张一, age=2, cole=大红脸)
//User(name=张二, age=3, cole=正宗黄种人)
//User(name=张三, age=4, cole=大红脸)
//User(name=张四, age=5, cole=黝黑透亮?黑无常:包大神)
//User(name=张四, age=6, cole=毫无血色?白无常:小白)
2、映射
操作 | 作用 |
---|---|
map | 接受Lambda,将元素转换成其他形式或提取信息,接受一个函数作为参数,该函数会被应用到每个元素并将其映射为一个新的元素。 |
flatMap | 接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连城一个流。 |
map同上
flatMap处理嵌套Stream,类似于addAll,将一个List中的全部元素添加到另一个List中。
List<String> str = Arrays.asList("aaa","bbb","ccc");
public static Stream<Character> getStr(String s){
List<Character> strs = new ArrayList<>();
for (Character s1:s.toCharArray()) {
strs.add(s1);
}
return strs.stream();
}
@Test
public void Test1() {
//用map结果是Stream<Stream<Character>>
// Stream<Stream<Character>> streamStream = str.stream().map(TestStream::getStr);
//用flatMap结果是Stream<Character>
// Stream<Character> characterStream ==str.stream().flatMap(TestStream::getStr);
str.stream().flatMap(TestStream::getStr).forEach(System.out::println);
}
//*******************控制台*********************
// a
// a
// a
// b
// b
// b
// c
// c
// c
3、排序
操作 | 作用 |
---|---|
sorted() | 自然排序 |
sorted(Comparator com) | 定制排序 |
区别:sorted()按照已有的Comparable排序(eg:String中的compareTo)
sorted(Comparator com)自己写按什么排序。
//sorted()
List<String> str = Arrays.asList("ddd", "aaa", "ccc", "bbb");
str.stream()
.sorted()
.forEach(System.out::println);
//*******************控制台*********************
// aaa
// bbb
// ccc
// ddd
list.stream()
.sorted((x,y)->{
if (x.getAge() == y.getAge()) { //年龄相同按姓名排
return x.getName().compareTo(y.getName());
} else {
return x.getAge().compareTo(y.getAge()); //否则按年龄排
}
})
.forEach(System.out::println);
//*******************控制台*********************
// User(name=张一, age=2, cole=大红脸)
// User(name=张二, age=3, cole=正宗黄种人)
// User(name=张三, age=4, cole=大红脸)
// User(name=张四, age=5, cole=黝黑透亮?黑无常:包大神)
// User(name=张四, age=6, cole=毫无血色?白无常:小白)
4、终止操作
操作 | 作用 |
---|---|
allMatch | 检查是否全部匹配 |
anyMatch | 检查是否至少匹配一个元素 |
noneMath | 检查是否没有匹配元素 |
findFirst | 找到第一个元素 |
findAny | 返回当前流汇中任意元素 |
count | 返回总数 |
max | 最大 |
min | 最小 |
【注】返回的结果为Optional的原因:返回的结果可能为空,避免空指针
//通用数据
List<User> list = Arrays.asList(
new User("张一", 2, "大红脸", 1),
new User("张二", 3, "正宗黄种人", 2),
new User("张三", 4, "大红脸", 1),
new User("张四", 5, "黝黑透亮?黑无常:包大神", 2),
new User("张五", 6, "毫无血色?白无常:小白", 1));
//1、allMatch是否全部人都是1(男的)
System.out.println(list.stream().allMatch(u -> u.getSex() == 1));
/*******************控制台*********************
/**
* false
*/
//2、anyMatch是否有人是男的
System.out.println(list.stream().anyMatch(u -> u.getSex() == 1));
/*******************控制台*********************
/**
* true
*/
//3、noneMatch没有人既不是男的又不是女的
System.out.println(list.stream().noneMatch(u -> u.getSex() == 3));
/*******************控制台*********************
/**
* true
*/
//【注:findxxx通常与过滤、排序共用】
//4、findFirst得到第一个
System.out.println(list.stream().findFirst());
/*******************控制台*********************
/**
* Optional[User(name=张一, age=2, cole=大红脸, sex=1)]
*/
//5、findAny得到第一个
System.out.println(list.stream().findAny());
/*******************控制台*********************
/**
* Optional[User(name=张一, age=2, cole=大红脸, sex=1)]
*/
//6、count得到总数
System.out.println(list.stream().count());
/*******************控制台*********************
/**
* 5
*/
//7、max最大值
System.out.println(list.stream().max(Comparator.comparing(User::getAge)));
/*******************控制台*********************
/**
* Optional[User(name=张五, age=6, cole=毫无血色?白无常:小白, sex=1)]
*/
//8、min最小值
System.out.println(list.stream().min(Comparator.comparing(User::getAge)));
/*******************控制台*********************
/**
* Optional[User(name=张一, age=2, cole=大红脸, sex=1)]
*/
规约
操作 | 作用 |
---|---|
reduce(T identity,BinaryOperator b) | 可以将流中元素反复结合起来得到一个值,返回的是T。 |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来得到一个值,返回的是Optional。 |
//reduce(BinaryOperator b),0作为第一次的初始值,然后每次累加后的值作为x去加y。因为初值为0不会出现空的情况不会出现空指针所以返回的是integer
List<Integer> list2 = Arrays.asList(1,2,3,4,5,6,7);
System.out.println(list2.stream().reduce(0, (x, y) -> x + y));
/*******************控制台*********************
/**
* 28
*/
//reduce(T identity,BinaryOperator b)
System.out.println(list.stream().map(User::getAge).reduce(Integer::sum));
/*******************控制台*********************
/**
* Optional[20]
*/
*/
收集
操作 | 作用 |
---|---|
collect | 将流转化为其他形式。接收一个Collector接口的实现,用于给Steam总元素做汇总的方法。----Collectors提供了很多静态方法便于创建常用收集器。 |
//将结果放入到某种集合中
list.stream().map(User::getName).collect(Collectors.toList());
list.stream().map(User::getName).collect(Collectors.toSet());
list.stream().map(User::getName).collect(Collectors.toCollection(HashSet::new));
list.stream().collect(Collectors.counting()); //总数
list.stream().collect(Collectors.averagingDouble(User::getAge)); //平均值
list.stream().collect(Collectors.summarizingInt(User::getAge)); //平均值
list.stream().collect(Collectors.maxBy((x,y)->Integer.compare(x.getAge(),y.getAge()))); //最大值
list.stream().collect(Collectors.minBy((x,y)->Integer.compare(x.getAge(),y.getAge()))); //最大值
list.stream().collect(Collectors.groupingBy(User::getSex));//根据性别分组
System.out.println(JSON.toJSON(list.stream().collect(Collectors.groupingBy(User::getSex, Collectors.groupingBy(u -> {
if (u.getAge() > 3) {
return "小孩";
} else {
return "老了";
}
}))))); //根据性别分组后再根据年龄分组
/*******************控制台(工具格式化后)*********************
/**
* {
* "1": {
* "小孩": [
* {
* "sex": 1,
* "name": "张三",
* "cole": "大红脸",
* "age": 4
* },
* {
* "sex": 1,
* "name": "张五",
* "cole": "毫无血色?白无常:小白",
* "age": 6
* }
* ],
* "老了": [
* {
* "sex": 1,
* "name": "张一",
* "cole": "大红脸",
* "age": 2
* }
* ]
* },
* "2": {
* "小孩": [
* {
* "sex": 2,
* "name": "张四",
* "cole": "黝黑透亮?黑无常:包大神",
* "age": 5
* }
* ],
* "老了": [
* {
* "sex": 2,
* "name": "张二",
* "cole": "正宗黄种人",
* "age": 3
* }
* ]
* }
* }
*/
System.out.println(list.stream().collect(Collectors.partitioningBy(user -> user.getAge() > 5)));//分组(满足在true组,不满足false组)
/*******************控制台*********************
/**
* {false=[User(name=张一, age=2, cole=大红脸, sex=1), User(name=张二, age=3, cole=正宗黄种人, sex=2), User(name=张三, age=4, cole=大红脸, sex=1), User(name=张四, age=5, cole=黝黑透亮?黑无常:包大神, sex=2)], true=[User(name=张五, age=6, cole=毫无血色?白无常:小白, sex=1)]}
*/
DoubleSummaryStatistics collect = list.stream().collect(Collectors.summarizingDouble(User::getAge));//对年龄的各种操作如下图
System.out.println(list.stream().map(User::getName).collect(Collectors.joining(",","----","----")));
/*******************控制台*********************
/**
* ----张一,张二,张三,张四,张五----
*/
System.out.println(list.stream().map(User::getName).collect(Collectors.joining("大傻,")));//连接字符串
/*******************控制台*********************
//张一大傻,张二大傻,张三大傻,张四大傻,张五
开启并行流,提高效率:xxx.stream().parallel();