一、Lambda表达式
1.1、为什么使用Lambda表达式 Lambda表达式起步案例
下面源码注释是传统写法,代码是简写表达式写法
java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.function.Consumer;
/*
* 学什么?
* 1、Lambda表达式
* 2、Stream API
* 3、Optional类 NullPointerException
* 目前存在的问题?
* 方法不能作为参数传递
* 如何解决这个问题?
* 行为参数化
* */
public class MyTest02 {
public static void main(String[] args) {
//匿名内部类
/*Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello Java8");
}
});
th1.start();*/
Thread th1 = new Thread(() -> {
System.out.println("hello Java8");
});
th1.start();
ArrayList<String> list = new ArrayList<String>();
list.add("111111");
list.add("11");
list.add("11222");
list.add("1");
/*Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//return o1.length() - o2.length();
return Integer.compare(o1.length(), o2.length());
}
});*/
// -> 后省略了大括号和return 还有o1,o2的String
Collections.sort(list, (o1,o2) -> Integer.compare(o1.length(), o2.length()));
System.out.println(list);
/*list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {//s -- 每次被遍历到的元素
System.out.println(s);
}
}); 下面是简写后的*/
list.forEach(s -> System.out.println(s));
list.forEach(System.out::println);
}
}
1.2、Lambda表达式写法
Lambda表达式是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格。使Java的语言表达能力得到了提升。
语法:
Lambda表达式操作符或箭头操作符:->
左侧:指定了Lambda表达式需要的参数列表(其实就是接口中的抽象方法的形参列表)
右侧:指定了Lambda体,是抽象方法的实现逻辑,也即Lambda表达式要执行的功能(其实就是重写的抽象方法的方法体)。
先把匿名内部类的对象找出来,再看方法参数和方法体
即源码
java
package day33;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.function.Consumer;
/*
* 学什么?
* 1、Lambda表达式
* 2、Stream API
* 3、Optional类 NullPointerException
* 目前存在的问题?
* 方法不能作为参数传递
* 如何解决这个问题?
* 行为参数化
* Lambda表达式
* -> Lambda操作符或箭头操作符
* 左侧:方法的参数列表
* 右侧:方法的方法体
* 方法:重写的方法
* Lambda表达式简写/进阶写法
* 1、如果参数列表没有参数,要写成()
* 2、如果参数列表有参数
* 参数个数>=2 (数据类型1 参数名1,数据类型2 参数名2,数据类型3 参数名3)
* 参数个数>=2 (参数名1, 参数名2,参数名3) !!!!!
* 只有一个参数 (数据类型 参数名)
* 只有一个参数 (参数名)
* 只有一个参数 参数名 !!!!!
* 3、右侧 - 如果方法体有多行代码,必需写{}
* 4、右侧 - 如果方法体只有一行代码,不用写{},不用写return,不用写结尾的";"
* */
public class MyTest02 {
public static void main(String[] args) {
//匿名内部类
/*Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello Java8");
}
});
th1.start();*/
Thread th1 = new Thread(() -> {
System.out.println("hello Java8");
});
th1.start();
ArrayList<String> list = new ArrayList<String>();
list.add("111111");
list.add("11");
list.add("11222");
list.add("1");
/*Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//return o1.length() - o2.length();
return Integer.compare(o1.length(), o2.length());
}
});*/
// -> 后省略了大括号和return 还有o1,o2的String
Collections.sort(list, (o1,o2) -> Integer.compare(o1.length(), o2.length()));
System.out.println(list);
/*list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {//s -- 每次被遍历到的元素
System.out.println(s);
}
}); 下面是简写后的*/
list.forEach(s -> System.out.println(s));
list.forEach(System.out::println);
}
}
1.3、函数式接口_@Functional注解
@FunctionalInterface
@Override
作用:编译器帮我们检查标注了该注解的接口是不是函数式接口
|-- 是 -- 编译通过
|-- 不是 -- 无法编译通过
注意:该注解的作用只是检查的作用,可以不写
相关源码显示:
java
package day33;
public class MyTest03 {
public static void aaa(MyInterface a, int m , int n) {
a.test(m,n);
}
public static void main(String[] args) {
/*aaa(new MyInterface() {
@Override
public void test(int a, int b) {
System.out.println(a + ":" + b);
}
},1,2);*/
aaa((a,b) -> System.out.println(a + ":" + b),1,2);
}
}
java
package day33;
@FunctionalInterface
public interface MyInterface {
void test(int a , int b);
//唯一的一个抽象方法
}
---------------------自己定义的,Java官方也有
1.4、函数式接口_常见函数式接口说明

1.5、复合的Lambda表达式
比较器复合 和 谓词复合
java
package day34;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Predicate;
//比较器复合
public class MyTest02 {
public static void main(String[] args) {
ArrayList<Apple> list = new ArrayList<>();
list.add(new Apple(150,"red"));
list.add(new Apple(210,"red"));
list.add(new Apple(300,"yellow"));
list.add(new Apple(90,"green"));
list.add(new Apple(90,"yellow"));
list.add(new Apple(100,"green"));
list.add(new Apple(123,"red"));
//按照重量降序排序
//list.sort(Comparator.comparing(Apple::getWeight).reversed());
//按照重量降序排序,如果重量相同那就按照颜色的升序排序
/*list.sort(Comparator.
comparing(Apple::getWeight)
.reversed()
.thenComparing(Apple::getColor));*/
//.thenCompareing(Comparator.comparing(Apple::getColor).reversed()));
//list.removeIf(item -> item.getWeight() == 90);
//删除颜色不是红颜色的苹果 Predicate的复合即谓词复合
Predicate<Apple> redApple = item -> item.getColor().equals("red");
//list.removeIf(redApple.negate());
//去除红颜色并且重量大于150的苹果
list.removeIf(redApple.and(item -> item.getWeight() > 150));
//去除红色并且重量大于150的苹果或绿苹果
list.removeIf(redApple.and(item -> item.getWeight() > 150).or(item -> item.getColor().equals("green")));
list.forEach(System.out::println);
}
}
二、方法引用
1、本质:就是Lambda表达式,对Lambda表达式的简写
2、比如类名::方法名,一般带两个冒号的就是
什么情况下Lambda表达式可以改成方法引用?
1)Lambda表达式的方法体只有一行代码,并且只调用了一个方法
2)除了参数列表和1)中的"一个方法",没有再引入其他的额外的内容

三、Stream_中间操作
3.1、filter 过滤符合条件的
java
package day34;
import java.util.ArrayList;
public class MyTest04 {
public static void main(String[] args) {
//filter -- 中间操作
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
//在控制台打印长度大于2的字符串
list.stream()
.filter(item -> item.length() > 2) //--> Stream
.forEach(System.out::println);
System.out.println("--------------------------------");
System.out.println(list);
}
}
3.2、distinct 去重
java
import java.util.ArrayList;
public class MyTest04 {
public static void main(String[] args) {
//filter -- 中间操作
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
//在控制台打印长度大于2的字符串
/*list.stream()
.filter(item -> item.length() > 2) //--> Stream
.forEach(System.out::println);
System.out.println("--------------------------------");
*/
//去除重复
list.stream()
.distinct() //根据元素的equals和hashCode方法判断是否重复
.forEach(System.out::println);
System.out.println("--------------------------------");
ArrayList<Apple> list1 = new ArrayList<>();
list1.add(new Apple(150,"red"));
list1.add(new Apple(210,"red"));
list1.add(new Apple(300,"yellow"));
list1.add(new Apple(90,"green"));
list1.add(new Apple(90,"yellow"));
list1.add(new Apple(90,"yellow"));
list1.add(new Apple(100,"green"));
list1.add(new Apple(123,"red"));
list1.stream()
.distinct()
.forEach(System.out::println);
}
}
3.3、limit 截断流 使其元素不超过给定数量
java
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
list1.stream()
.limit(3)
.forEach(System.out::println);
3.4、skip 跳过元素,返回一个扔掉了前n个元素的流,若元素不足n个,返回空流
java
list1.stream()
.skip(3)
.forEach(System.out::println);
3.5、map 映射 将流中的每个元素进行转换
3.5.1、传统做法
java
package day34;
import java.util.ArrayList;
import java.util.LinkedHashSet;
public class MyTest05 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
//map - 映射 - 将流中的每个元素进行转换
//获取list中每个字符串的长度并在控制台打印
list.stream()//String
.map(s -> s.length())//长度
.forEach(System.out::println);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//获取list中每个字符串的长度并在控制台打印,去除重复的长度
list.stream()
.map(String::length)
.distinct()
.forEach(System.out::println);
System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
//传统做法
LinkedHashSet<Integer> setLength = new LinkedHashSet<>();
for (String s : list) {
setLength.add(s.length());
}
for (Integer len : setLength) {
System.out.println(len);
}
}
}
3.5.2、flatMap 把多个流合并成一个流
java
System.out.println("__________________________________________");
list.stream()
.mapToInt(String::length)
.distinct()
.forEach(System.out::println);
ArrayList<String> list1 = new ArrayList<>();
list1.add("Hello");
list1.add("World"); //H e l l o W o r l d
list1.stream() //String
.map(s -> s.split("")) //String --> String[]
.flatMap(arr -> Arrays.stream(arr)) //String[] --> Stream -->Stream合并
.forEach(System.out::println);
/* 传统的 上面的是新的
String[] arr = "hahaha".split("");
System.out.println(Arrays.toString(arr));*/
四、Stream_终端操作
补forEach:没有返回值
4.1、allMatch_anyMatch_noneMatch
java
package day34;
import java.util.ArrayList;
public class MyTest06 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
//list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
boolean flag = list.stream()
.allMatch(s -> s.length() > 2); //判断所有元素是否达到要求
System.out.println(flag);
boolean flag1 = list.stream()
.anyMatch(s -> s.length() > 2); //判断是否有元素是否达到要求
System.out.println(flag1);
boolean flag2 = list.stream()
.noneMatch(s -> s.length() > 2); //判断没有任何元素达到要求
System.out.println(flag2);
}
}
4.2、findFirst_findAny
java
package day34;
import java.util.ArrayList;
import java.util.Optional;
public class MyTest06 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
//list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
boolean flag = list.stream()
.allMatch(s -> s.length() > 2); //判断所有元素是否达到要求
System.out.println(flag);
boolean flag1 = list.stream()
.anyMatch(s -> s.length() > 2); //判断是否有元素是否达到要求
System.out.println(flag1);
boolean flag2 = list.stream()
.noneMatch(s -> s.length() > 2); //判断没有任何元素达到要求
System.out.println(flag2);
Optional<String> first = list.stream().findFirst(); //获取第一个元素
System.out.println(first.get());
Optional<String> any = list.stream().findAny(); //获取任意一个元素
System.out.println(any.get());
}
}
4.3、reduce
!!!!!归约!!!!!
之前见到过的终端操作都是返回一个boolean(allMatch之类的)、void(forEach)或Optional对象(findAny)等。使用reduce操作来表达更复杂的查询,此类查询需要将流中所有元素反复结合起来,得到一个值,比如一个Integer.这样的查询可以被归类为归约操作(将流归约成一个值)
java
package day34;
import java.util.Arrays;
import java.util.Optional;
public class MyTest07 {
public static void main(String[] args) {
Integer[] arr = new Integer[]{1,2,3};
/*Integer sum = Arrays.stream(arr)
.reduce(0, (n1, n2) -> n1 + n2);*/
/*Integer sum = Arrays.stream(arr)
.reduce(0, (n1, n2) -> Integer.sum(n1, n2));*/
Integer sum = Arrays.stream(arr)
.reduce(0, Integer::sum);
System.out.println(sum);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Optional<Integer> sum1 = Arrays.stream(arr)
.reduce(Integer::sum);
System.out.println(sum1.get());
//最大值
/*Integer max = Arrays.stream(arr)
.reduce(arr[0], (n1, n2) -> {
if (n1 > n2) {
return n1;
} else {
return n2;
}
});*/
/* Integer max = Arrays.stream(arr)
.reduce(arr[0], (n1, n2) -> n1 > n2 ? n1 : n2);*/
/*Integer max = Arrays.stream(arr)
.reduce(arr[0], (n1, n2) -> Integer.max(n1, n2));*/
Integer max = Arrays.stream(arr)
.reduce(arr[0], Integer::max);
System.out.println("Max = " + max);
Optional<Integer> max1 = Arrays.stream(arr)
.reduce(Integer::max);//没有起始值的
System.out.println("Max1 = " + max1.get());
//最小值
Integer min = Arrays.stream(arr)
.reduce(arr[0], Integer::min);
System.out.println("Min = " + min);
//最佳实践:包装类判断值是否相同要使用equals判断
Integer i1 = 1000;
Integer i2 = 1000;
System.out.println(i1 == i2);//不行
System.out.println(i1.equals(i2));
}
}
小练习:
怎样用map 和 reduce 方法计算流中元素的数据。
java
//计算流中的元素个数
//把元素值都变成1,累加起来即为sum
Integer count = Arrays.stream(arr)
.map(item -> 1)
.reduce(0, Integer::sum);
System.out.println(count);
4.4、sorted
java
package day34;
import java.util.ArrayList;
import java.util.Comparator;
public class MyTest08 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
//list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
list.stream()
.sorted() //自然排序
.forEach(System.out::println);
System.out.println("==============================================");
/*list.stream()
.sorted((s1, s2) -> Integer.compare(s1.length(), s2.length()))
.forEach(System.out::println);*/
list.stream()
.sorted(Comparator.comparingInt(String::length).reversed().thenComparing(String::compareTo))
.forEach(System.out::println);
System.out.println("-----------------------------------------------");
System.out.println(list.stream().count());
}
}
4.5、Stream的终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值。例如:List、Integer,甚至是void。
流进行了终止操作后,不能再次使用。
java
package day35;
import java.util.ArrayList;
import java.util.stream.Stream;
public class MyTest01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
Stream<String> stream = list.stream();
stream.map(item -> 1).forEach(System.out::println);
//流一旦进行了终端操作就不能再重复使用,报错
stream.map(item -> 1).forEach(System.out::println);
}
}
4.5.1、匹配与查找
java
package day35;
import java.util.ArrayList;
import java.util.Optional;
import java.util.stream.Stream;
public class MyTest01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
System.out.println(list.stream().count());
Optional<String> max = list.stream()
//.max((s1, s2) -> s1.compareTo(s2));
.max(String::compareTo);
System.out.println(max.get());
}
}
4.6、collect

java
package day35;
import java.util.*;
import java.util.stream.Collectors;
public class MyTest02 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Aqaa");
list.add("Bssss");
list.add("Cwww");
list.add("Ddsdd");
list.add("Edadc");
/*ArrayList<Integer> nums = new ArrayList<>();
list.stream()
.map(String::length)
.forEach(len -> nums.add(len));
System.out.println(nums);*/
List<Integer> nums = list.stream()
.map(String::length)
.collect(Collectors.toList());//把流当中的元素给搜集到集合里面,并作为元素返回
Set<Integer> nums1 = list.stream()
.map(String::length)
.collect(Collectors.toSet());//Set方法自动去重,Collectors可省略
TreeSet<Integer> num2 = new TreeSet<>(nums1);//合并转换
System.out.println(num2);
System.out.println(nums1);
System.out.println("------------------------------------------------");
String s = list.stream()
.map(str -> str.substring(0, 1))
.collect(Collectors.joining("+"));
System.out.println(s);
//例子:搜集所有参与交易的交易员姓名到一个集合中
/*List<String> names = transactions.stream()
.map(Transaction::getTrader)
.map(Trader::getName)
.distinct
.collect(Collectors.toList());
System.out.println(names);*/
}
}