Lambda表达式
① 语法
lambda表达式 ,是JDK1.8新增的特性
使用新的运算符 -> (转到、称为)
lambda表达式的组成
第1部分: (参数)
第2部分: ->
第3部分: 方法体,可以是表达式也可以是代码块
例如:
(parameters) -> expression
或
(parameters) ->{ statements; }
解释:
1.参数类型可以不写 (a,b) -> {return a+b;}
2.如果方法体中只有1行代码,{}也可不写 (a,b) -> return a+b;
3. 参数只有1个的时候,前面()也可以不写 a -> return a*a;
② 示例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
③ 在哪里以及如何使用Lambda
接口中只有1个抽象方法,才能使用lambda表达式
Lambda表达式初衷为了简化匿名内部类的语法。
提到到一个概念:函数式编程
由于匿名内部类,虽然没有名字,但是还是要给出方法的定义。
函数式接口,即适用于函数式编程场景的接口。
而Java中的函数式编程体现就是Lambda,所以函数式接口就是可
以适用于Lambda使用的接口。
只有确保接口中有且仅有一个抽象方法,
Java中的Lambda才能顺利地进行推导。
④ 示例
示例1
1> 使用匿名内部创建接口对象
Comparator<Dog> c=new Comparator<Dog>() {
@Override
public int compare(Dog o1, Dog o2) {
return o1.getAge()-o2.getAge();
}
};
Collections.sort(list,c);
2> Lambda表达式
Collections.sort(list,(o1,o2)->o1.getAge()-o2.getAge());
示例2: 使用Lambda表达式实现Runnable接口
查看API发现Runnable接口只有1个抽象方法
public interface Runnable {
public abstract void run();
}
示例3:使用Lambda表达式创建ActionListener接口对象
//查看ActionListener接口源码
public interface ActionListener extends EventListener {
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e);
}
// 只有1个抽象方法,则可以使用Lambda表达式简写
示例4:使用Lambda表达式遍历集合
JDK1.8 Iterable<T>接口提供一个默认方法
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
forEach方法的作用: 遍历集合内容
发现这个方法的参数Consumer是一个接口,且接口中只有1个抽象方法
public interface Consumer<T> {
void accept(T t);
}
//就可以使用Lambda表达式实现接口式编程
package lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class Demo5 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("jack");
list.add("rose");
//遍历输出集合中的内容
//以前可以使用 for,迭代器,foreach//JDK1.8提供一个方法快速遍历集合中内容
//方式1:使用匿名内部类创建接口Consumer
Consumer<String> action=new Consumer<String>() {
@Override
public void accept(String t) {
System.out.println(t);
}
};
list.forEach(action);
//方式2:使用Lambda表达式
list.forEach((t) -> System.out.println(t));
//简写
list.forEach(t -> System.out.println(t));
//更简写
list.forEach(System.out::println);
}
}
示例5 使用Lambda表达式和函数式接口 Predicate
Predicate功能:过滤
在java.util.function 包中有一个接口Predicate
查看API发现这个接口中只有1个抽象方法
public interface Predicate<T>{
boolean test(T t) ;
}
//可以添加逻辑,例如可以过滤集合中的数据
default Predicate<T> and(Predicate<? super T> other)
返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND。
static <T> Predicate<T> isEqual(Object targetRef)
返回根据 Objects.equals(Object, Object)测试两个参数是否相等的 谓词 。
default Predicate<T> negate()
返回表示此谓词的逻辑否定的谓词。
default Predicate<T> or(Predicate<? super T> other)
返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或。
boolean test(T t)
在给定的参数上评估这个谓词。
package lambda;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
// 可以使用Lambda表达式创建接口对象,要求这个接口中只有1个抽象方法
public class PredicateDemo2 {
public static void main(String[] args) {
// 使用匿名内部类创建接口
Predicate<String> tj0 = new Predicate<String>() {
@Override
public boolean test(String t) {
if (t.endsWith("a")) {
return true;
}
return false; // 返回返回值类型必须是boolean
}
};
// 过滤条件1
Predicate<String> tj1 = t -> t.startsWith("J");
// 过滤条件2
Predicate<String> tj2 = t -> t.length() == 4;
// Predicate一般用于过滤集合中内容
List<String> list=Arrays.asList("Java","Peee","JSwing","Python");
//输出所有
System.out.println("------输出所有-------");
list.forEach(System.out::println);
//对list存储内容进行一些过滤 list集合中提供stream方法filter过滤
// filter方法的参数 Stream<T> filter(Predicate<? super T> predicate);
System.out.println("----------满足条件tj1的元素-------");
list.stream().filter(tj1).forEach(System.out::println);
System.out.println("----------满足条件tj2的元素-------");
list.stream().filter(tj2).forEach(System.out::println);
System.out.println("同时满足条件1和条件2");
list.stream().filter(tj1.and(tj2)).forEach(System.out::println);
}
}
Stream 对集合的增强操作
1 它与 java.io包中InputStream和OutputStream完全不同的概念。
2 JDK1.8 引入Stream,是对集合对象功能的增强。
Stream它专注于对集合对象进行各种非常便利高效的操作
例如: 一个集合中存储客户所有信息,可以求出客户每月平均的消费金额
取出集合中前10个商品作为首页推荐
3 Stream 有三大特点
Stream不存储元素
Stream不会修改其数据源
Stream的执行具有延迟特性
Stream
先获取一个数据源(Source) ---> 数据转换 ---->执行操作获取想要的结果
每次转换原来的Stream对象不会改变都会生成一个新的Stream对象
就可以链式调用转换的功能。
1> 如何创建Stream对象
情况1: 从数组获取Stream对象
Integer[] arr = { 1, 2, 3, 4, 5, 6 }; //数组对象
//方式1: Arrays.stream方法创建Stream对象
Stream<Integer> stream1=Arrays.stream(arr);
stream1.forEach(System.out::println);
//方式2: Stream.of方法
Stream<Integer> stream2=Stream.of(1,2,3,4,5);
stream2.forEach(System.out::println);
情况2:集合
List<Integer> list=Arrays.asList(1,2,3,4);
//普通流
Stream<Integer> stream01=list.stream();
//并行流(并行能力,多线程使用)
Stream<Integer> stream02=list.parallelStream();
2> Stream转换成数组、集合
1> Stream —> 数组
String[] arr= {"a","b","c"};
Stream<String> stream1=Arrays.stream(arr);
String[] newArr=stream1.toArray(String[]::new);
// String[]::new 等价于 创建一个new String[stream1元素个数];
System.out.println(Arrays.toString(newArr));
2> Stream—>List、Set、Stack
List<String> list=Arrays.asList("a","b","c","a");
//将list--->Stream
Stream<String> stream1=list.stream();
//将Stream ---> list
List<String> list2=stream1.collect(Collectors.toList());
System.out.println(list2);
//将Stream ---> Set
Set<String> set1=stream1.collect(Collectors.toSet());
System.out.println(set1);
//将Stream ---> Stack
Stack<String>
stack=stream1.collect(Collectors.toCollection(Stack::new));
2> 流的操作
中间操作: 会返回一个新的Stream对象,可以继续执行下一个中间操作
filter:过滤,符合条件的数据被留下来生成一个新Stream
sorted:排序,对Stream中元素进行排序,排序后的的数据生成一个新Stream
distinct:去掉重复值,将不重复的元素生成一个新的Stream
map: map接口一个函数作为参数,该函数作用用于流每一个元素遍历
遍历流中每一个元素,生成一个新Stream对象
flatMap: 将每一个元素被拆分一个新的流
limit:截断流,返回一个不超过给定长度的新Stream对象
终端操作: 返回的结果,终端操作此流的生命周期结束。
forEach() 遍历流中每一个元素,会关闭流
findFirst()
findAny()
allMatch 要求所有Stream中所有元素都满足条件才返回true
noneMatch 要求所有的元素都不满足条件才返回true
anyMatch, 只要有1个元素满足就返回true
reduce: 把Stream中元素按照一种规则串起来
字符串拼接,数值类型元素avg,sum,max,min
count : 返回Stream中元素的个数
collect:实际项目中用的很多,将Stream转换成数组,List、Set、Stack等等
Map集合进行分组
groupingBy:分组条件
3> 中间操作
① filter 过滤`
filter:过滤,符合条件的数据被留下来生成一个新Stream
Integer[] arr= {1,2,3,4,5};
// Stream<Integer> stream=Arrays.stream(arr);
// //输出偶数
// Stream<Integer> stream2=stream.filter(t-> t%2==0);
// //再将stream2转换成数组
// Integer[] arr2=stream2.toArray(Integer[]::new);
// System.out.println(Arrays.toString(arr2));
Integer[] evens=Stream.of(arr).
filter(t->t%2==0).toArray(Integer[]::new);
Stream.of(evens).forEach(System.out::println);
② sorted 排序
sorted:排序,对Stream中元素进行排序,排序后的的数据生成一个新Stream
代码示例:
Integer[] arr = { 1, 34, 15, 7, 8 };
Integer[] arr2 = Stream.of(arr).sorted().
toArray(Integer[]::new);
Stream.of(arr2).forEach(System.out::println);
// 倒序
Integer[] arr3 = Stream.of(arr).
sorted((o1, o2) -> -(o1 - o2) ).
toArray(Integer[]::new);
Stream.of(arr3).forEach(System.out::println);
③ distinct 去重
distinct:去掉重复值,将不重复的元素生成一个新的Stream
代码示例:
Integer[] arr = { 1, 2, 1, 2, 1, 2, 3 };
Integer[] arr2=Stream.of(arr).distinct().
toArray(Integer[]::new);
Stream.of(arr2).forEach(System.out::println);
④ map 遍历Stream中每一个元素1:1
map: 将一个接口函数作为参数,该函数作用用于流每一个元素遍历
遍历流中每一个元素,生成一个新Stream对象
代码示例: 将数组中字符串首字母转换成大写
// 将字符串字符变成大写
String[] arr = { "jack", "rose" };
String[] arr2=Stream.of(arr).
map(t->t.toUpperCase()).toArray(String[]::new);
Stream.of(arr2).forEach(System.out::println);
List<String> list=new ArrayList<>();
list.add("jack"); list.add("rose");
List<String> list2=list.stream().map(t->t.toUpperCase()).
collect(Collectors.toList());
System.out.println(list2);
List<Integer> list3=Arrays.asList(1,2,3,4);
List<Integer> list4=list3.stream().map(t->t*t).
collect(Collectors.toList());
System.out.println(list3+"---"+list4);
⑤ flatMap 将每一个元素拆分成一个新的流
List<String> x= Arrays.asList("a","b");
List<String> y= Arrays.asList("1","2");
List<String[]> list=x.stream()
.flatMap(i->y.stream().map(j->new String[] {i,j}))
.collect(Collectors.toList());
System.out.println(list.size());
for(String[] arr:list) {
System.out.println(Arrays.toString(arr));
}
运行结果:
4
[a, 1]
[a, 2]
[b, 1]
[b, 2]
⑥ limit 截取
String[] arr= {"a","b","c","d"};
String[] arr2=Stream.of(arr).limit(2).toArray(String[]::new);
System.out.println(Arrays.toString(arr2));//[a, b]
4> 终端操作
返回的结果,终端操作此流的生命周期结束。
forEach() 遍历流中每一个元素,会关闭流
findFirst()
findAny()
allMatch 要求所有Stream中所有元素都满足条件才返回true
noneMatch 要求所有的元素都不满足条件才返回true
anyMatch, 只要有1个元素满足就返回true
reduce: 把Stream中元素按照一种规则串起来
字符串拼接,数值类型元素avg,sum,max,min
count : 返回Stream中元素的个数
collect:实际项目中用的很多,将Stream转换成数组,List、Set、Stack等等
Map集合进行分组
groupingBy:分组条件
① allMatch、anyMatch、noneMatch
List<Person> list=new ArrayList<>();
list.add(new Person(1,"jack",10));
list.add(new Person(2,"rose",15));
list.add(new Person(3,"hehe",36));
//List集合中每一个Person对象都必须满足这个条件,返回true
boolean flag=list.stream().allMatch(t->t.getAge()>=18);
System.out.println(flag);
//List集中有任意一个满足,返回true
boolean flag2=list.stream().anyMatch(t->t.getAge()>=18);
System.out.println(flag2);
//List集合中都不满足,返回true
boolean flag3=list.stream().noneMatch(t->t.getAge()>=18);
System.out.println(flag3);
② findFirst、findAny
String[] arr= {"jack","rose","jack","jack2"};
Stream.of(arr).filter(t->"jack".equals(t)).findAny()
.ifPresent(System.out::println); //找到满足条件的第1个
③ reduce
1> 参数为BinaryOperator
// R apply(T t, U u)
// Optional<T> reduce(BinaryOperator<T> accumulator)
int sum2=Stream.of(1,2,3,4,5).reduce((t,u)->t+u).get();
System.out.println(sum2);
//输出最大值5
int max=Stream.of(1,2,3,4,5).reduce((t,u)-> t>=u? t:u).get();
System.out.println(max);
2> 有2个参数 T reduce(T identity, BinaryOperator<T> accumulator)
多一个泛型T,实际上相对于在计算值的时候多一个初始化的值
int sum3=Stream.of(1,2,3,4,5).reduce(0,(t,u)->t+u);
System.out.println(sum3);
分组
1> 哪里使用分组
如何分组?
调用collect方法,参数可以传递分组
collect(Collectors.groupingBy(分组条件));
2> IntSummaryStatistics 类
DoubleSummaryStatistics类
LongSummaryStatistics类
统计数据的收集状态,如count,min,max,sum和average。
double getAverage()
返回记录的值的算术平均值,如果没有记录值,则返回零。
long getCount()
返回记录的值的计数。
int getMax()
返回记录的最大值,如果没有记录值,则返回 Integer.MIN_VALUE 。
int getMin()
返回记录的最小值,如果没有记录值,则返回 Integer.MAX_VALUE 。
long getSum()
返回记录的值的总和,如果没有记录值,则返回零。
3> 示例
一个班级每个学生都有如下信息
学生编号 学生姓名 学生年龄 学生性别 总学分
1001 张三 20 男 6.0
1002 李四 18 女 4.0
1003 王五 17 男 3.5
1004 赵六 21 男 6.0
需求1: 统计此班级的男生和女生人数?
需求2: 获取本班男生中总学分最高的分数
需求3: 求出本班的男生的平均分?
需求4: 求出本班的平均年龄?
public class Student {
private int stuNo;
private String stuName;
private int stuAge;
private char stuSex;
private double stuScore;
}
package groupby;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Demo {
public static void main(String[] args) {
Student s1 = new Student(1001, "张三", 20, '男', 6.0);
Student s2 = new Student(1002, "李四", 18, '女', 4.0);
Student s3 = new Student(1003, "王五", 17, '男', 3.5);
Student s4 = new Student(1004, "赵六", 21, '男', 6.0);
List<Student> list = Arrays.asList(s1, s2, s3, s4);
// groupingBy(按什么字段分组,去Collectors找相关的方法)
// Collectors.counting() 统计个数
// 需求1: 统计此班级的男生和女生人数?
Map<Character, Long> map1 = list.stream()
.collect(Collectors.groupingBy(Student::getStuSex,
Collectors.counting()));
System.out.println(map1);
// 需求2: 获取本班男生中总学分最高的分数
// 先分析:根据什么属性分组
// summarizingDouble 用于求最大值,最小值,求和
Map<Character, DoubleSummaryStatistics> map2 =
list.stream().collect(Collectors.groupingBy(Student::getStuSex, // 按照性别分
组
Collectors.summarizingDouble(Student::getStuScore) // 将分数
进行聚合运算
));
System.out.println("所有男的总学分:" + map2.get('男').getSum());
System.out.println("男生最高学分:" + map2.get('男').getMax());
System.out.println("男生最低学分:" + map2.get('男').getMin());
System.out.println("男生的平均分:" + map2.get('男').getAverage());
System.out.println("男生的个数:" + map2.get('男').getCount());
// 需求3: 求出本班的男生的平均分?
// 需求4: 求出本班的平均年龄?
Double v = list.stream().collect(Collectors.
averagingDouble(Student::getStuAge));
System.out.println(v);
}
}
Stream的常用方法
中间操作:
Stream<T> distinct() 去重
Stream<T> filter(Predicate<? super T> predicate) 过滤
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>>
mapper) 1:n映射
Stream<T> limit(long maxSize) 获取指定个数元素的Stream
<R> Stream<R> map(Function<? super T,? extends R> mapper)
IntStream mapToInt(ToIntFunction<? super T> mapper) 将对象某个属性为int
字段存入IntStream中
Stream<T> sorted() 返回由此流的元素组成的流,根据自然顺序排序。
Stream<T> sorted(Comparator<? super T> comparator)
终端操作:
boolean allMatch(Predicate<? super T> predicate) Stream中所有元素否满足条
件才返回true
boolean anyMatch(Predicate<? super T> predicate) Stream中有任意一个元素满
足条件返回true
boolean noneMatch(Predicate<? super T> predicate) Stream中所有元素都不满足
条件返回true
<R,A> R collect(Collector<? super T,A,R> collector) 将Stream转换成 数
组、List、Set
结合groupingBy分组
使用转换map
Optional<T> findAny()
Optional<T> findFirst()
void forEach(Consumer<? super T> action) 遍历Stream中元素
Optional<T> max(Comparator<? super T> comparator)
根据提供的 Comparator返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator)
根据提供的 Comparator返回此流的最小元素。
Optional<T> reduce(BinaryOperator<T> accumulator)