目前本人对于Lambda 理论并不是很了解,先上代码操作吧,后续学习在把理论补上!!!
**一:基本操作**
Integer[] str = {1, 3, 2, 6, 7, 2};
// List<Integer> list= Arrays.asList(str);
//不用System.out.println(list); 这样就可以输出 2,6,4
// list.stream().filter(a->a%2==0).forEach(System.out::println);
//这样会返回list
// List<Integer> collect = list.stream().filter(a -> a % 2 == 0).collect(Collectors.toList());
//System.out.println(collect);
//数组符合条件和去重 distinct()
// Arrays.stream(str).filter(a->a%2==0).distinct().forEach(System.out::println);
//数组符合条件和去重返回指定个数元素 distinct() limit()
//Arrays.stream(str).filter(a->a%2==0).distinct().limit(1).forEach(System.out::println);
//数组符合条件和去重 skip 跳过指定元素,返回剩余元素的流,与limit互补。
//List<Integer> collect = Arrays.stream(str).filter(a -> a % 2 == 1).skip(1).collect(Collectors.toList());
//System.out.println(collect);
//返回true 或 false
// Arrays.stream(str).map(a->a%2==0).forEach(System.out::println);
//用Stream
// List<Integer> integers = Arrays.asList(str);
// Stream.iterate(0,i->i+1).limit(2).forEach(i-> System.out.println(integers.get(i)));
// 排序正序 和 反序
//List<Integer> integers = Arrays.asList(str);
/*Collections.sort(integers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2); //反序前面加个 - 就行
}
});
System.out.println(integers);
}*/
// 排序正序 和 反序 lambda
/* List<Integer> integers = Arrays.asList(str);
Collections.sort(integers, (Integer a1, Integer a2) -> {
return -a1.compareTo(a2);
});
System.out.println(integers);*/
//在简写 排序正序 和 反序 lambda
/*List<Integer> integers = Arrays.asList(str);
Collections.sort(integers,(a1,a2)-> -a1.compareTo(a2));
System.out.println(integers);*/
//reduce 求和
List<Integer> integers = Arrays.asList(str);
Integer reduce = integers.stream().reduce(0, (a, b) -> a + b);
//或者
Integer reduce1 = integers.stream().reduce(0, Integer::sum);
System.out.println(reduce1);
若是没有初始值则:
利用Integer 的sum和max 等方法
Optional<Integer> reduce = list.stream().map(Integer::intValue).reduce(Integer::sum);
Optional<Integer> reduce1 = list.stream().map(Integer::intValue).reduce(Integer::max);
//map 主要对传入的参数做逻辑处理 仔细体会 map 和 filter
filter 用于判断真假的 i->i==3,map 用于处理过程 例如 i->i*3
// List<Integer> integers = Arrays.asList(str);
//输出 2,6,4,12,14,4
//integers.stream().map(i->i*2).forEach(System.out::println);
//输出 0,2,4 若不加limit(integers.size()) 则会无限输出 !!!!!
// Stream.iterate(0,i->i+1).limit(integers.size()).filter(i->i%2==0).forEach(System.out::println);
//求值:
List<Integer> integers=Arrays.asList(str);
IntSummaryStatistics intSummaryStatistics = integers.stream().mapToInt((a) -> a).summaryStatistics();
//获取最大值
intSummaryStatistics.getMax();
//获取最小值
intSummaryStatistics.getMin();
//求和 对比reduce
intSummaryStatistics.getSum();
//求数量
intSummaryStatistics.getCount();
//求平均
intSummaryStatistics.getAverage();
或者利用:
Collectors.averagingInt Collectors.averagingLong Collectors.averagingDouble
//将一个对象的集合转化为另一个对象的集合
List<OrderDetail> orderDetailList = orderDetailService.listOrderDetails();
List<CartDTO> cartDTOList = orderDetailList.stream()
.map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
.collect(Collectors.toList());
**理论**:(1)诸如filter和sorted等中间操作会返回一个流。这让多个操作可以连接起来查询。重要的是,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理--他们很懒。这是因为中间操作一般都可以合并起来,在终端操作时一次性全部处理(并行处理)。终端操作会从流的流水线上生成结果。其结果是任何不是流的值,比如返回list ,integer 甚至void 非Stream 的值 。
(2): 流是从支持数据处理操作的源生成的一系列元素
(3):流操作有两类:中间操作和终端操作。
(4):流当中的元素是按需计算的。
(5):foreach 和count等终端操作会返回一个非流的值,并处理流水线返回结果,是一次性消费。而且foreach 处理元素时并不一定是以顺序处理元素的,要想顺序处理元素必须用forEachOrdered。
(6):
**二:四大核心函数式接口**
//1:利用函数是接口Consumer 输出值
Consumer<Integer>consumer=(x)->{ System.out.println("ww:"+x); };
//这样可以直接输出
consumer.accept(22);
//2: 利用函数是接口Supplier 输出值
Supplier<Integer>supplier =()->{String s="hello Word";
int length = s.length();
return length;
};
Integer aa=supplier.get();
System.out.println(aa);
//3: 利用函数是接口Function 输出值(求最大值)
Function<List<Integer>, Integer> function=(x)->{int a=x.size();
Integer v=x.get(a-1);
return v;
};
List<Integer> list = Arrays.asList(1, 2, 3);
Integer apply = function.apply(list);
System.out.println(apply);
//4: 利用函数是接口Predicate 输出值
//该接口实现,输入一个T类型的值,然后返回一个boolean类型。
//例如,输入一个字符串,判断该字符串的长度是否大于10。
Predicate<String> predicate =
(x) -> {
int n = x.length();
if (n > 10) {
System.out.println("n 大于 10");
return true;
}else {
System.out.println("n 小于 10");
return false;
}
};
predicate.test("Hello world!");
//5 函数复合 Function 复合配有: andThen compose (执行以下代码去理解)
public int compute(int a, Function<Integer,Integer>function1,Function<Integer,Integer>function2){
return function1.compose(function2).apply(a);
}
public int compute1(int a, Function<Integer,Integer>function1,Function<Integer,Integer>function2){
return function1.andThen(function2).apply(a);
}
public int compute3(int a,int b,BiFunction<Integer,Integer,Integer>function2){
return function2.apply(a,b);
}
public int compute4(int a,int b,BiFunction<Integer,Integer,Integer>function5,Function<Integer,Integer>function6){
return function5.andThen(function6).apply(a,b);
}
//compose 讲解 先执行value -> value * value 2*2=4 把4作为vaule 后4 * 3=12 所以最后结果为12
LJController ljController=new LJController();
int compute = ljController.compute(2, value -> value * 3, value -> value * value);
System.out.println("compute 多个值是:"+compute);
int compute1 = ljController.compute1(2, value -> value * 3, value -> value * value);
System.out.println("compute1 多个值是:"+compute1);
int i = ljController.compute3(1, 2, (value1, value2) -> value1 % value2);
System.out.println(i);
int compute4= ljController.compute4(1, 2, (value1, value2) -> value1 % value2,value->value + value);
System.out.println(compute4);
Function<Integer, Integer> identity = Function.identity();
Integer apply = identity.apply(6);
System.out.println(apply);
理论:(1)对于三个参数的构造函数语言本身没有提供所以这种时候你可以自己创一个。
例如:
public interface Trifunction<T,U,V,R>{
R apply(T t,U u,V v);
}
Trifunction<Integer, Integer,Integer,Color>colorFactory=Color::new;
**三:基本语法:**
在Java8中,引入了一个新的操作符”->”,该操作符将lambda表达式拆分成两个部分:
lambda表达式的参数列表,位于”->”操作符左边
lambda表达式所执行的功能,即lambda体。位于”->”操作符右边。
一个lambda表达式的基础语法是
(type1 param1, type2 param2, ...)->{
statements;
}
编译器对待一个lambda表达式就如同它是从一个匿名内部类创建的对象。
简单来说,lambda表达式的参数列表就是函数式接口中抽象方法的参数列表,lambda体就是该方法的方法体。
以本文开头的代码为例,EventHandler接口仅有一个方法,并且该方法具有一个ActionEvent类型的参数,所以编译器可以自动推断出e是一个ActionEvent类型的参数,并且花括号里面的内容为handle方法的方法体。
如果EventHandler接口中含有多个方法,编译器将无法编译lambda表达式,可以看出,lambda表达式是根据编译器的隐式推断来简化代码的。所以,==lambda表达式需要函数式接口的支持==。
明白了lambda表达式的运行机制,下面就是常见的lambda表达式的语法格式:
函数式接口中的方法无参数,例子如下:
() ->{//do something}
若方法体只有一个语句,return和花括号都可以省略不写。
函数式接口中的方法有参数,例子如下:
(int x, int y) -> {//do something}
表达式中参数的类型可以不写,编译器可以通过上下文推断出其类型,上面的代码可以简化如下:
(x, y) ->{do something}
如果只有一个参数,参数列表的括号可以省略,例子如下:
x ->{//do something}
四:转化:
list->set 则:Collectors.toSet()
list->map 则:Collectors.toMap()
五:方法引用:
学习自:https://www.cnblogs.com/xiaoxi/p/7099667.html(自己总结稍后加)
https://blog.csdn.net/timheath/article/details/71194938(讲的比较好)
1:类名::静态方法名 这个是调用静态方法的
2:对于两个非静态的方法则是:例如 同一class
public void tt(){
}
public void gg(){
tt()
}
不同class则是:
public calss RR{
public void tt(){
}
}
public void gg(){
RR rr=new RR();
rr::tt
}
六:特殊操作:
(1): 原始类型流特化
IntStream DoubleStream LongStream 特化为 int long double 从而避免了 暗含的装箱的成本。
(2):映射到数值流
将流转化为特化版本的常用方法是mapToInt,mapToDouble,mapToLong, 他们原理和map是一样的只是返回一个特化流,而不是Stream<T>。例如,你可以像mapToInt中对menu的卡路里求和: //到这返回一个IntStream
int calories=meau.stream().mapToInt(Dish::getCalories).sum()
这里如果流是空的sum默认返回0。IntStream还支持max ,min ,average。
(3):转化回对象流 boxed()
IntSream intStream=meau.stream().mapToInt(Dish::getCalories)
Stream<Integer>stream=intStream.boxed();
(4) :默认值OptionalInt
求和那个例子很容易,因为他有一个默认值:0。但是你要计算IntStream中最大的元素就得换个法子。如何区分没有元素的流和最大值真是0的流?对于三种原始类型特化版本:OptionalInt OptionalDouble OptionalLong 。
例如:要找到IntStream中最大的元素,可以调用max 方法他会返回一个OptionalInt :
OptionalInt optionalInt=meau.stream().mapToInt(Dish::getCalories).max();
现在如果没有默认值的话你就可以显示的处理OptionalInt去定义一个默认值:
Int max=optionalInt.orElse(1);
(5) :产生数值范围
用IntStream 和LongStream 帮助生成数值范围:range 和rangeClosed。
这俩个方法都是第一个参数接起始值,第二个参数接收结合值。但是range 是不包含结束值的,而rangeClosed则包含结束值。例子:
IntStream intStream=IntStream. rangeClosed(1,100).filter(n->n%2==0)
System.out.println(intStream.count());
(6):连接字符串 joining 内部利用StringBuilder把字符串逐个追加起来
String collect2 = list1.stream().map(String::toString).collect(Collectors.joining());
System.out.println(collect2);
加个“,” String collect2 = list1.stream().map(String::toString).collect(Collectors.joining(","));
输出 1,2,4,2,6。
(7):**特别注意**
String::toString 代表集合中的每个元素 Integer::intValue 代表集合中的每个元素
(8):groupingBy 返回一个map 自己理解
Integer [] str={1,3,2,3,6,4,2};
Map<Integer, List<Integer>> collect2 = list.stream().collect(groupingBy(Integer::intValue));
System.out.println(collect2);
{1=[1], 2=[2, 2], 3=[3, 3], 4=[4], 6=[6]}
// 输出 {1=1, 2=2, 3=2, 4=1, 6=1} 1是1个 2是2个
Map<Integer, Long> collect3 = list.stream().collect(groupingBy(Integer::intValue, counting()));
(9):并行流转化为顺序流
概念:并行流就是一个内容分为多个数据块,并用 不同的线程分别处理每个数据块的流。可以实现自动把给定操作的工作负荷分配给多核处理器的多个内核,让他们也忙起来
用 sequential() 这个方法
(10) :声明一个空的Optional对象
Optional.empty():
例子:Optional<Car>oldCar=Optional.empty();
依据一个非空值创建Optional
Optional<Car>oldCar=Optional.of(car);如果car是null 则抛出NullPointerException,而不是等你访问car 的时候才返回一个错误
(11) :map 和flatmap
先举个错误的例子:
Optional<Person>optperson=Optional.of(person);
optperson.map(Person::getCar).map(Car::getInsurce).map(Insurce::getName)
因为getCar 操作的是Optional<Car>类型的对象这意味着map操作的是 Optional<Optional<Car>> 因此对getInsurce 调用是非法的,map(Car::getInsurce) 写的是Car.
正确的是:optperson.flatMap(Person::getCar).flatMap(Car::getInsurce).map(Insurce::getName) 。这里如果Optiona结果默认值为空,则可以设置默认值:
optperson.flatMap(Person::getCar).flatMap(Car::getInsurce).map(Insurce::getName).orElse("Unknow")
理论详解:https://blog.csdn.net/Mark_Chao/article/details/80810030 写的很生动
flatmap 处理的的是多个对象流合为一个流 map 处理的是一个对象一个流返回也是一个流(若是map 处理的是多个流则返回多个流)