函数式接口
java.util.function
Java 8 最常用的四个函数式接口
- 消费型接口:Consumer void accept(T t) 接受一个输入参数,不返回任何结果。accept
public class ConsumerTest {
/**
* Consumer 是一个函数式接口,它接受一个参数并不返回任何结果。我们可以使用它来对一组元素进行操作。
*/
@Test
public void test1(){
Consumer<String> print = str -> System.out.println(str);
print.accept("hello"); // 输出 "hello"
}
@Test
public void test2(){
List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());
list.forEach(printUpperCase); // 输出 "APPLE", "BANANA", "PEAR", "ORANGE"
}
}
- 供给型接口:Supplier T get() 不接受任何输入参数,返回一个结果。get
public class SuppilerTest {
/**
* Supplier 是一个函数式接口,它不接受任何参数,但返回一个结果。我们可以使用它来生成值。
*/
@Test
public void test1(){
Supplier<Integer> random = () -> new Random().nextInt(100);
int result = random.get(); // 返回 0~99 中的一个随机数
System.out.println(result);
}
@Test
public void test2(){
Supplier<List<String>> defaultList = () -> Arrays.asList("apple", "banana", "pear", "orange");
List<String> list = defaultList.get(); // 返回 ["apple", "banana", "pear", "orange"]
}
}
- 函数型接口:Function<T,R> R apply(T t) 接受一个输入参数,返回一个结果。apply
public class FunctionTest {
/**
* Function 是一个函数式接口,它接受一个参数并返回一个结果。我们可以使用它来进行各种转换和映射。
*/
@Test
public void test1() {
Function<String, String> toUpperCase = str -> str.toUpperCase();
String result = toUpperCase.apply("hello"); // 返回 "HELLO"
System.out.println(result);
}
@Test
public void test2() {
List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
Function<String, Integer> length = str -> str.length();
list.stream()
.map(length)
.collect(Collectors.toList())
.forEach(System.out::println); // 返回 [5, 6, 4, 6]
}
}
- 判断型接口:Predicate boolean test(T t) 接受一个输入参数,返回一个布尔值结果。test
public class PredicateTest {
/**
* Predicate 是一个函数式接口,它接受一个参数并返回一个布尔值。
* 我们可以使用它来实现各种过滤器和检查器。
*/
@Test
public void test1() {
Predicate<String> isEmpty = str -> str.isEmpty();
boolean result = isEmpty.test(""); // 返回 true
}
@Test
public void test2() {
List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
Predicate<String> startsWithA = str -> str.startsWith("a");
list.stream()
.filter(startsWithA)
.collect(Collectors.toList())
.forEach(System.out::println); // 返回 ["apple"]
}
}
方法引用
当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
Stream流
【Java 8 新特性】Java Stream通过peek()为每个元素提供消费函数
Stream流:生成操作,中间操作,终结操作,收集操作以及它们的常用方法
IntermediateOperations中间操作
public class IntermediateOperations {
private static List<Employee> list = EmployeeData.getEmployees();
/**
* 1、filter(): 返回结果生成新的流中只包含满足筛选条件的数据。
*/
@Test
public void test() {
list.stream().forEach(System.out::println);
}
@Test
public void testFilter() {
list.stream().filter(emp -> emp.getName().startsWith("马"))
.forEach(System.out::println);
}
/**
* 2、map():将流中的元素进行再次加工形成一个新流,流中的每一个元素映射为另外的元素。
*/
@Test
public void testMap() {
list.stream().map(emp -> emp.getName())
.forEach(System.out::println);
list.stream().map(emp -> emp.getId())
.forEach(System.out::println);
}
/**
* 3、flatMap():扁平化映射,它具体的操作是将多个stream连接成一个stream,
* 这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用。
*/
@Test
public void testFlatMap() {
List<Integer> num1 = Arrays.asList(1, 2, 3);
List<Integer> num2 = Arrays.asList(4, 5, 6);
List<Integer> num3 = Arrays.asList(7, 8, 9);
List<List<Integer>> lists = Arrays.asList(num1, num2, num3);
lists.forEach(System.out::println);
lists.stream().flatMap(l -> l.stream())
.forEach(System.out::println);
}
/**
* 4、distinct():顾名思义,将流中的元素去重之后输出。
*/
@Test
public void testDistinct() {
list.stream().map(s -> s.getAge()).distinct()
.forEach(System.out::println);
}
/**
* 5、sorted():这个很简单了,顾名思义,将流中的元素按照自然排序方式进行排序。
*/
@Test
public void testSorted() {
// sorted:自然顺序排序
list.stream().map(s -> s.getAge()).sorted()
.forEach(System.out::println);
System.out.println();
// sorted:降序排序
list.stream().map(s -> s.getAge()).sorted(Comparator.reverseOrder())
.forEach(System.out::println);
System.out.println();
// sorted:使用Comparator
list.stream().map(s -> s.getAge()).sorted(Comparator.comparing(n -> n))
.forEach(System.out::println);
System.out.println();
}
/**
* 6、peek():对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。
* peek方法主要用于调试,以便在元素流过管道中的某个点时查看它们。
* 在Java9中,对于像count()这样的短路操作,peek方法中的操作不会被这些元素调用。
* peek方法不向流中注入元素或从流中移除元素。
* 在流源中,元素的数量是已知的,count是流列表的大小,因此不需要执行管道。
*/
@Test
public void testPeek() {
Stream.of("GG", "HH", "JJ")
.peek(System.out::println) //a,b,c,d
.count();
Stream.of("ma", "zhi", "chu")
.filter(e -> e.length() > 2)
.peek(System.out::println)
.collect(Collectors.toList());
}
/**
* 7、limit():顾名思义,返回指定数量的元素的流。返回的是Stream里前面的n个元素。
*/
@Test
public void testLimit() {
Stream.of(4, 7654, 4, 23, 5, 76, 8, 67, 76)
.limit(3)
.forEach(System.out::println);
}
/**
* 8、skip():和limit()相反,将前几个元素跳过(取出)再返回一个流,
* 如果流中的元素小于或者等于n,就会返回一个空的流。
*/
@Test
public void testSkip() {
Stream.of(4, 7654, 4, 23, 5, 76, 8, 67, 76)
.skip(3)
.forEach(System.out::println);
}
}
TerminalOperations 终结操作
public class TerminalOperations {
private static List<Employee> list = EmployeeData.getEmployees();
/**
* forEachOrdered()
* 并行流(parallel stream)中,forEach()方法可能不一定遵循顺序
*/
@Test
public void testForEach() {
list.stream().map(Employee::getAge)
.forEach(System.out::println);
list.parallelStream().map(Employee::getAge)
.forEach(System.out::println);
}
/**
* forEachOrdered()
* 始终按照流(stream)中元素的遇到顺序执行给定的操作
*/
@Test
public void testForEachOrdered() {
list.stream().map(Employee::getAge)
.forEachOrdered(System.out::println);
list.parallelStream().map(Employee::getAge)
.forEachOrdered(System.out::println);
}
/**
* * min()
* * max()
* * count()
*/
@Test
public void testCountMinMax() {
System.out.println(
list.stream()
.map(Employee::getAge)
.count());
System.out.println(
list.stream()
.map(Employee::getAge)
.min(Integer::compare)
.get());
System.out.println(
list.stream()
.map(Employee::getAge)
.max(Integer::compare).get());
}
/**
* toArray()
*/
@Test
public void testToArray() {
Object[] array = list.stream().map(Employee::getAge)
.toArray();
System.out.println(Arrays.toString(array));
Integer[] array1 = list.stream().map(Employee::getAge)
.toArray(Integer[]::new);
System.out.println(Arrays.toString(array1));
}
/**
* reduce()
*/
@Test
public void testReduce() {
final Optional<Integer> reduce = list.stream().map(Employee::getAge)
.reduce(Integer::sum);
System.out.println(reduce);
}
/**
* collect()
*/
@Test
public void testCollect() {
final List<Integer> collect = list.stream().map(Employee::getAge)
.collect(Collectors.toList());
System.out.println(collect);
}
/**
* anyMatch
*/
@Test
public void testAnyMatch() {
boolean is = list.stream().map(Employee::getName)
.anyMatch(s -> s.startsWith("马"));
System.out.println(is);
is = list.stream().map(Employee::getName)
.anyMatch(s -> s.startsWith("周"));
System.out.println(is);
}
/**
* allMatch
*/
@Test
public void testAllMatch() {
boolean is = list.stream().map(Employee::getAge)
.allMatch(s -> s < 100);
System.out.println(is);
is = list.stream().map(Employee::getAge)
.allMatch(s -> s > 100);
System.out.println(is);
}
/**
* noneMatch
*/
@Test
public void testNoneMatch() {
boolean is = list.stream().map(Employee::getAge)
.noneMatch(s -> s < 100);
System.out.println(is);
is = list.stream().map(Employee::getAge)
.noneMatch(s -> s > 100);
System.out.println(is);
}
/**
* findFirst
*/
@Test
public void testFindFirst() {
Optional<Integer> first = list.stream().map(Employee::getAge)
.findFirst();
System.out.println(first);
}
/**
* findAny
*/
@Test
public void testFindAny() {
Optional<Integer> any = list.stream()
.map(Employee::getAge)
.filter(s -> s > 45)
.findAny();
System.out.println(any);
}
}
collect : toList, toSet, toMap
public class CollectTest {
private static List<String> list = new ArrayList<>();
static {
Collections.addAll(list, "gina-男-29", "Komen-男-22",
"Rose-男-23", "Feman-女-26", "ken-男-29", "Miny-女-20",
"Jeff-女-22", "Roy-男-28", "Jack-女-24");
}
@Test
public void test1() {
list.forEach(System.out::println);
}
/**
* 收集到list
*/
@Test
public void test2() {
final List<String> collect = list.stream()
.filter(str -> "男".equals(str.split("-")[1]))
.collect(Collectors.toList());
System.out.println(collect);
}
/**
* 收集到set
*/
@Test
public void test3() {
final Set<String> collect = list.stream()
.filter(str -> "男".equals(str.split("-")[1]))
.collect(Collectors.toSet());
System.out.println(collect);
}
/**
* 收集到map
* toMap:
* 参数1:key的生成规则
* Function:
* 泛型1:流中每个数据的类型
* 泛型2:map集合中key的数据类型
* apply形参:流中的每个数据
* 方法体中的返回值:生成的key
* 参数2:value的生成规则
* Function:
* * 泛型1:流中每个数据的类型
* * 泛型2:map集合中value的数据类型
* * apply形参:流中的每个数据
* * 方法体中的返回值:生成的value
* <p>
* 注意:key不能重复
*/
@Test
public void test4() {
Map<String, Integer> map1 = list.stream()
.filter(str -> "男".equals(str.split("-")[1]))
.collect(Collectors.toMap(
new Function<String, String>() {
@Override
public String apply(String s) {
return s.split("-")[0];
}
}
, new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s.split("-")[2]);
}
}
));
System.out.println(map1);
Map<String, Integer> map2 = list.stream()
.filter(str -> "男".equals(str.split("-")[1]))
.collect(Collectors.toMap(str -> str.split("-")[0],
str ->Integer.parseInt(str.split("-")[2])));
System.out.println(map2);
}
}
三个练习题
public class ExerTest1 {
/**
* 数据过滤:过滤奇数
*/
@Test
public void test1() {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
final List<Integer> collect = list.stream()
.filter(x -> x % 2 == 0)
.toList();
System.out.println(collect);
}
/**
*
*/
@Test
public void test2() {
List<String> list = new ArrayList<>();
Collections.addAll(list, "gina,29", "Komen,22", "Rose,23", "Femany,26",
"ken,29", "Min,20", "Jeff,22", "Roy,28", "Jack,24");
final Map<String, Integer> map = list.stream()
.filter(x -> Integer.parseInt(x.split(",")[1]) >= 24)
.collect(Collectors.toMap(
str -> str.split(",")[0],
str -> Integer.parseInt(str.split(",")[1])));
System.out.println(map);
}
@Test
public void test3() {
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
Collections.addAll(list1, "ken,29", "joe,22", "Femany,26",
"ken,29", "Jeff,22", "Jack,24");
Collections.addAll(list2, "Rose,23", "Femany,26", "Min,20",
"Roy,28", "gina,28", "Rrunny,28");
Stream<String> s1 = list1.stream()
.filter(s -> s.split(",")[0].length() == 3)
.limit(2);
Stream<String> s2 = list2.stream()
.filter(s -> s.split(",")[0].startsWith("R"))
.skip(1);
// Stream.concat(s1, s2)
// .map(new Function<String, Actor>() {
// @Override
// public Actor apply(String s) {
// String name = s.split(",")[0];
// int age = Integer.parseInt(s.split(",")[1]);
// return new Actor(age, name);
// }
// })
// .forEach(System.out::println);
List<Actor> collect = Stream.concat(s1, s2)
.map(s -> new Actor(Integer.parseInt(s.split(",")[1]),
s.split(",")[0]))
.collect(Collectors.toList());
System.out.println(collect);
}
}
public class Actor {
private Integer age;
private String name;
public Actor(Integer age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Actor{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}