lamabda表达式与函数式接口
函数式接口:接口中只有一个未实现的方法
@FuncationalInterface:检查注解,检查写的接口是否是函数式接口
lambda表达式简化了实例的创建
接口MyInterface
@FunctionalInterface//检查注解:检查写的接口是否是函数式接口
public interface MyInterface {
int sum(int i, int j);
//默认实现
default int defaultSum(int i, int j) {
return i *j;
}
}
创建匿名实现类(冗余写法)
MyInterface myInterface1 = new MyInterface() {
@Override
public int sum(int i, int j) {
return i*i + j*j;
}
};
System.out.println(myInterface1.sum(3, 4));
lambda表达式,语法糖,完整写法
只保留动态的内容
语法: (参数列表…) -> {方法体积}
MyInterface myInterface2 = (int i,int j) -> {
return i*i + j*j;
};
System.out.println(myInterface2.sum(5,6));
简化写法:
参数类型可以不写,只写(参数名…),参数变量名随便定义
参数表最少可以只有一个(),或者只有一个参数名
方法体如果只有一句话,{}可以省略
MyInterface myInterface3 = (i,j) -> i*i + j*j;
lambda表达式使用
入门
var list = new ArrayList<String>();
list.add("zyl");
list.add("hcx");
list.add("cmh");
//倒序排列
Collections.sort(list, (o1,o2) -> o2.compareTo(o1));
System.out.println(list);
//:: 引用类中的实例方法
//只能正序排列
Collections.sort(list, String::compareTo);
new Thread(
() -> System.out.println("hello world")
).start();
}
何时使用lambda表达式:
1.以后调用某个方法传入参数,
这个参数实例是一个接口对象,且只定义一个方法
Function函数式的各种写法
函数式接口:只包含一个抽象方法接口,是支持lambda表达式基础
lambda表达式需要一个目标类型,
这个目标类型必须是一个函数式接口
函数式接口出入参定义:
1.有入参,无出参
消费者
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
使用
BiConsumer<Integer,Integer> biConsumer = (a,b) -> System.out.println(a+b);
biConsumer.accept(5,6);
2.有入参,有出参
多功能函数
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
使用
Function<String,Integer> function1 = str-> Integer.parseInt(str);
Function<String,Integer> function2 = Integer::parseInt;
Integer applyInteger = function1.apply("5");
3.无入参,无出参
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
示例:
Runnable runnable = () -> System.out.println("hello");
4.无入参,有出参
数据提供者
@FunctionalInterface
public interface Supplier<T> {
T get();
}
示例:
Supplier<String> supplier = ()-> "hello";
String result = supplier.get();
java.util.function包下的所有funcation定义:
1.consumer 消费者
2.supplier 提供者
3.predicate 断言
Predicate<Integer> predicate = integer -> 5 == integer;
boolean isEqual = predicate.test(10);
应用:
public static void main(String[] args) {
//1.定义数据提供者函数
Supplier<String> supplier = () -> "hello world!";
String dataProvider = supplier.get();
//2.断言
Predicate<String> predicate = str -> str.contains("!");
boolean isTrue = predicate.test(dataProvider);
//3.转化
Function<String,String> function = String::toUpperCase;
String applyUpper = function.apply(dataProvider);
System.out.println(applyUpper);
//4.消费
Consumer<String> consumer = upper -> System.out.println(upper.toLowerCase());
consumer.accept(applyUpper);
}
将4步合在一起
if (predicate.test(supplier.get())) {
consumer.accept(function.apply(supplier.get()));));
} else {
System.out.println(" is false");
}
Stream Api
声明式处理集合数据:筛选,转换,组合等
创建流->
中间操作(filter,map,flatMap)->新流->
终止操作(count.max)->结果
特性:
懒加载,不用,方法就不会被调用
step1先把数据封装成流,要到数据流
step2.定义流式操作
step3.获取最终结果
1.挑出最大偶数
说明:
filter:过滤出想要的值,如果断言返回true,就是需要的值
intermediate operation,中间操作
max: 求最大值,terminal operation 终止操作
实现:
List<Integer> integerList = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//挑出最大的偶数
integerList.stream()
.filter(item -> item % 2 == 0)
.max(Integer::compareTo)
.ifPresent(System.out::println);
ifPresent(item -> System.out.println(t))
简化
ifPresent(System.out::println);
全类名::方法名
流的3大部分:
1.数据流
1-1创建流
concat():合并,将2个流合并成一个流
1-2从集合容器中获取流
List/Set/Map
2.中间操作
流默认是不并发的
long count = integerList.stream()
.filter(item -> {
System.out.println("filter thread:" + Thread.currentThread().getName());
System.out.println("now filter:" + item);
return item > 2;
})
.count();
System.out.println(count);
将流变成并发流
long count = integerList.stream()
.parallel()
.filter(item -> {
System.out.println("filter thread:" + Thread.currentThread().getName());
System.out.println("now filter:" + item);
return item > 2;
})
.count();
System.out.println(count);
有并发数据将产生并发安全问题,需自行解决多线程安全问题
流的所有所有状态都是无状态,数据状态仅在此函数内有效,不溢出至函数外
错误写法:
var newList = new ArrayList<Integer>();
long count = integerList.stream()
.parallel()
.filter(item -> {
System.out.println("filter thread:" + Thread.currentThread().getName());
System.out.println("now filter:" + item);
//不能将流中数据溢出至函数外
newList.add(item);
return item > 2;
})
.count();
解决:加锁
脱裤子放屁,别开并发就行
var newList = new ArrayList<Integer>();
long count = integerList.stream()
.parallel()
.filter(item -> {
synchronized (Objects.class) {
System.out.println("filter thread:" + Thread.currentThread().getName());
System.out.println("now filter:" + item);
newList.add(item);
return item > 2;
}
})
.count();
使用线程安全list
也没必要,直接不用并发流就好
List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<Integer>());
long count = integerList.stream()
.parallel()
.filter(item -> {
synchronizedList.add(item);
System.out.println("filter thread:" + Thread.currentThread().getName());
System.out.println("now filter:" + item);
return item > 2;
})
.count();
stream中间操作
filter:过滤,挑出要用的元素
map:映射,一一映射,a变成b
mapToInt/mapToLong/mapToDouble
flatMap:散列,一多映射
准备数据
引入lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
private String sex;
private Integer age;
}
集合:
List<Person> nameList = List.of(
new Person("周 一","男",20),
new Person("王 二","女",22),
new Person("赵 三","女",33),
new Person("赵 四","女",18)
);
filter案例:挑出年龄大于23的人
nameList.stream()
.parallel()
.filter(item -> item.getAge() > 18)
.forEach(System.out::println);
map案例:拿到这些人的姓名
nameList.stream()
.parallel()
.filter(item -> item.getAge() > 18)
.map(Person::getName)
.forEach(System.out::println);
floatMap:一对多
nameList.stream()
.parallel()
.filter(item -> item.getAge() > 18)
.map(Person::getName)
.flatMap(item -> {
String[] split = item.split(" ");
return Arrays.stream(split);
})
.forEach(System.out::println);
distinct:去重
sort:排序,默认升序
peek:将所有元素查看一遍,没有返回值,流不会更改
与forEach区别:forEach是结束操作,peek流没有关
limit:要几个元素
taskWhile:满足条件,拿到这个元素/当不满足条件,直接结束流操作
Stream.of(1,2,3,4,5,6,7,8,9,10)
.takeWhile( item -> item < 2)
.forEach(System.out::println);
只打印1
groupBy:分组
Map<String, List<Person>> groupList = nameList.stream()
.parallel()
.filter(item -> item.getAge() > 15)
.collect(Collectors.groupingBy(Person::getSex));
groupList.forEach((key, value) -> {
System.out.println(key + " : " + value);
});