知识模块:
一.方法引用
a.方法概述
b.方法引用格式
二.Stream流
1.Stream流概述
2.Stream流操作步骤
一.方法引用
a.方法概述
/*
方法引用概述:
当我们使用已有类中的方法作为Lambda表达式对应的接口中的抽象方法实现
我们可以用方法引用来简化Lambda表达式
*/
import org.junit.Test;
import java.util.function.Consumer;
/*
方法引用概述:
当我们使用已有类中的方法作为Lambda表达式对应的接口中的抽象方法实现
我们可以用方法引用来简化Lambda表达式
*/
public class MethodRef01 {
@Test
public void test01() {
Consumer<String> c = str -> System.out.println(str);
c.accept("abc");
System.out.println(System.out);//java.io.PrintStream@f5f2bb7
}
@Test
public void test02() {
//Consumer<String> c = str -> System.out.println(str);
Consumer<String>c=System.out::println; //System.out代表了我们要引用的类
//::后面的println代表我们引用的方法
c.accept("abc");
}
}
/*
class MethodRefDemo$$Lambda$1 implements Consumer<sTRING>{
public void accept(String str){
System.out.println(str);//我们使用是PrintStream类中的println(String str)方法
//作为str->System.out.println(str)对应的Consumer<String>
//中accept(String str)的实现
}
}
*/
b.方法引用格式
方法引用使用的前提:(适用于1,2)
引用的方法和Lambda表达式对应接口中的抽象方法中的形参类型保持一致
1.成员方法引用
a.引用非静态成员方法
/*
非静态成员引用
对象名::方法名
*/
import java.util.Objects;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person person)) return false;
return name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
import org.junit.Test;
import java.util.function.Consumer;
import java.util.function.Supplier;
/*
方法引用使用的前提:
引用的方法和Lambda表达式对应接口中的抽象方法中的形参类型保持一致
非静态成员引用
对象名::方法名
*/
public class MethodRefDemo02 {
Person p = new Person("老王");
@Test
public void test01() {
//Supplier<String >s=()->p.getName();
Supplier<String> s = p::getName;
System.out.println(s.get());
}
@Test
public void test02() {
//Consumer<String> c = name -> p.setName(name);
Consumer<String>c=p::setName;
c.accept("老李");
System.out.println(p);
}
@Test
public void test03() {
String str = "abc";
//Supplier<Integer> s = () -> str.length();
Supplier<Integer> s = str::length;
System.out.println(s.get());
}
@Test
public void test04() {
String str = "abc";
//Supplier<Character> s = () -> str.charAt(1);
/* Supplier<Character>s=str::charAt; //一个有参,一个无参,不能简化
System.out.println(s.get());*/
}
}
b.引用静态成员方法
/*
静态方法引用
类名::静态方法名
Arrays,Collections
Arrays类中
static String toString(int[] a)
返回指定数组内容的字符串表示形式。
Collections类
public static <T extends Comparable<? super T>> void sort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序
*/
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
/*
静态方法引用
类名::静态方法名
Arrays,Collections
Arrays类中
static String toString(int[] a)
返回指定数组内容的字符串表示形式。
Collections类
public static <T extends Comparable<? super T>> void sort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序
*/
public class MethodRefDemo03 {
@Test
public void test01() {
int[] arr = {3, 7, 9};
//Function<int[], String> f = array -> Arrays.toString(array);
Function<int[],String>f=Arrays::toString;
System.out.println(f.apply(arr));
}
@Test
public void test02() {
List<Integer> integers = Arrays.asList(1, 7, 12, 5, 23);
//Consumer<List<Integer>> c = list -> Collections.sort(list);
Consumer<List<Integer>> c = Collections::sort;
c.accept(integers);
System.out.println(integers);
}
}
2.构造方法引用
/*
构造方法引用格式:
类名::new
*/
3.数组对象引用
数组对象引用格式
类型[]::new
import org.junit.Test;
import java.util.function.Function;
/*
构造方法引用格式:
类名::new
数组对象引用格式
类型[]::new
*/
public class MethodRefDemo04 {
@Test
public void test01() {
//创建一个Person类的对象,获取这个对象
//Function<String, Person> f = name -> new Person(name);
Function<String, Person> f = Person::new;
System.out.println(f.apply("三丰"));
}
@Test
public void test02() {
//创建一个指定长度的数组,返回这个数组对象
//Function<Integer, int[]> f = n -> new int[n];
Function<Integer, int[]> f=int[]::new;
System.out.println(f.apply(4).length);
}
}
4.特殊的非静态方法
/*
特殊的非静态方法的引用
格式:
类名::非静态方法名
***1.不再适用于放啊引用的前提条件
2.当Lambda表达式第一个参数,作为实例(非静态)方法的调用者,第二个参数作为实例对象的参数,可以受用 类名::非静态方法名
3.当Lambda表达式的参数作为一个空参实例方法的调用者时候,也可使用 类名::非静态方法名
*/
import org.junit.Test;
import java.util.function.BiPredicate;
import java.util.function.Function;
/*
特殊的非静态方法的引用
格式:
类名::非静态方法名
1.不再适用于放啊引用的前提条件
2.当Lambda表达式第一个参数,作为实例(非静态)方法的调用者,第二个参数作为实例对象的参数,可以受用 类名::非静态方法名
3.当Lambda表达式的参数作为一个空参实例方法的调用者时候,也可使用 类名::非静态方法名
*/
public class MethodRefDemo05 {
@Test
public void test01() {
Person p1 = new Person("老王");
Person p2 = new Person("老李");
//BiPredicate<Person, Person> bp = (person1, person2) -> person1.equals(person2);
BiPredicate<Person, Person> bp = Person::equals;
System.out.println(bp.test(p1, p2));
}
@Test
public void test02() {
Person p1 = new Person("老王");
//Function<Person, String> f = person -> person.getName();
Function<Person, String> f = Person::getName;
System.out.println(f.apply(p1));
}
}
二.Stream流
1.Stream流概述
Strean流的出现是为了增强集合和数组的操作,Stream流更专注于数据的转换,过滤,获取等一系列操作
同时Stream流提高了操作集合和数组的小笼包,简化了代码
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/*
Stream流的概述
统计后缀名为.txt文件名称的个数
*/
public class StreamDemo01 {
@Test
public void test01() {
ArrayList<String> al = new ArrayList<String>();
al.add("1.txt");
al.add("2.txt");
al.add("3.pdf");
al.add("4.docx");
int count=0;
for (String s : al) {
if (s.endsWith(".txt")) {
count++;
}
}
System.out.println(count);
}
@Test
public void test02() {
List<String> list = Arrays.asList("1.txt", "2.txt", "3.pdf", "4.docx");
/*long count = list.stream().filter(str -> str.endsWith(".txt")).count();
System.out.println(count);*/
System.out.println(list.stream().filter(str -> str.endsWith(".txt")).count());
}
}
2.Stream流操作步骤
1.根据数据源获取一个Stream对象
/*
集合或数组流对象的获取
集合:
Collection体系:都是通过Stream()方法来获取一个流对象
List
Set
Map体系: 需要转换到Collection体系的集合,才能调用stream()方法获取一个流对象
HashMap
数组:
static <T> Stream<T> of(T... values)
返回一个元素为指定值的顺序排列的流。
*/
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Stream;
/*
集合或数组流对象的获取
集合:
Collection体系:都是通过Stream()方法来获取一个流对象
List
Set
Map体系: 需要转换到Collection体系的集合,才能调用stream()方法获取一个流对象
HashMap
数组:
static <T> Stream<T> of(T... values)
返回一个元素为指定值的顺序排列的流。
*/
public class StreamDemo02 {
@Test
public void test01() {
Stream<Stream> stream1 = new ArrayList<Stream>().stream();//Stream流上的泛型和集合中元素的类型相对应
//当我们通过集合对象来调用stream()方法,相当于
//将集合中的元素添加到Stream流中等待操作
Stream<Integer> stream2 = new HashSet<Integer>().stream();//Stream流上的泛型和集合中元素的类型相对应
}
@Test
public void test02() {
new HashMap<Integer,Stream>().keySet().stream();//需要将Map转换成Collection体系的集合,就可以使用stream()方法获取流对象
//将一个个key添加到stream中
new HashMap<Integer,String>().entrySet().stream();//将一个entry对象{key=value}添加到stream流中
}
@Test
public void test03() {
int[] arr = {1, 3, 9};
Stream<int[]> stream1 = Stream.of(arr);//如果通过基本类型数组获取一个流对象,此时六种只有一个元素:这个数组对象
Integer[] arr2 = {1, 3, 9};
Stream<Integer> stream2 = Stream.of(arr2);//我们通过基本类型对应的包装类的引用类型数组,获取流对象,此时相当于将数组中的元素添加到流中
Stream<String> stream3 = Stream.of("abc", "def", "ghk");//通过一串数据获取流对象
Stream<Integer> stream4 = Stream.of(3, 5, 7);
}
}
2.通过Stream对象可以进行0次或多次中间操作
/*
中间操作:
过滤操作
filter:传入一个Predicate,根据Predicate中的条件对流中的元素做一个筛选,满足条件保留,不满足的剔除
排序操作:
sorted:可以根据指定的规则,将流中的元素从小到大排序
去重操作
distinct:去除流中重复的元素
截取操作
limit:根据传入的值,来决定截取流总元素的个数
skip: 根据传入的值,决定跳过流中的元素个数
映射操作
map:讲义中数据根据指定操作映射成另一种数据
mapToInt
mapToDouble
mapToLong
*/
public class Student {
//学生姓名
private String name;
//语文成绩
private double chineseScore;
//数学成绩
private double mathScore;
public Student(String name, double chineseScore, double mathScore) {
this.name = name;
this.chineseScore = chineseScore;
this.mathScore = mathScore;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getChineseScore() {
return chineseScore;
}
public void setChineseScore(double chineseScore) {
this.chineseScore = chineseScore;
}
public double getMathScore() {
return mathScore;
}
public void setMathScore(double mathScore) {
this.mathScore = mathScore;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", chineseScore=" + chineseScore +
", mathScore=" + mathScore +
'}';
}
}
/*
中间操作:
过滤操作
filter:传入一个Predicate,根据Predicate中的条件对流中的元素做一个筛选,满足条件保留,不满足的剔除
排序操作:
sorted:可以根据指定的规则,将流中的元素从小到大排序
去重操作
distinct:去除流中重复的元素
截取操作
limit:根据传入的值,来决定截取流总元素的个数
skip: 根据传入的值,决定跳过流中的元素个数
映射操作
map:讲义中数据根据指定操作映射成另一种数据
mapToInt
mapToDouble
mapToLong
班级中有5个人姓名,语文成绩,数学成绩分别如下
李雷, 70, 90
韩梅梅, 30, 100
李宁, 85, 80
王松,70,60
张家界,90,73
需求:
1.打印语文成绩>80的学生信息
2.打印数学成绩前三名的学生信息
3.打印数学成绩倒数第一和倒数第二的学生信息
4.获取全班数学的平均成绩
5.获取全班语文成绩(不包含重复成绩)
6.将语文成绩或数学成绩在[80,90]之间的学生的姓名收集到一个集合中
*/
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class StreamDemo04 {
//@Before会在所有的@Test注解之前执行
List<Student> students;
@Before
public void init() {
//初始化数据源
students= Arrays.asList(
new Student("李雷", 70, 90),
new Student("韩梅梅", 30, 100),
new Student("李宁", 85, 80),
new Student("王松", 70, 60),
new Student("张家界", 90, 73)
);
}
@Test
public void test02() {
//1.打印语文成绩>80的学生信息
students.stream().filter(stu -> stu.getChineseScore() > 80).forEach(System.out::println);
}
@Test
public void test03() {
//2.打印数学成绩前三名的学生信息
/*
a.首先需要对学生的成绩从大到小排序
b.获取前三名的信息
*/
students.stream()
.sorted((stu1,stu2)->(int)(stu2.getMathScore()-stu1.getMathScore()))
.limit(3)//截取流中的前三个元素
.forEach(System.out::println);
}
@Test
public void test04() {
// 3.打印数学成绩倒数第一和倒数第二的学生信息
/*
a.首先需要对学生的数学成绩从大到小排序
b.获取倒数第一和倒数第二
*/
students.stream()
.sorted((stu1, stu2) -> (int) (stu2.getMathScore() - stu1.getMathScore()))
.skip(students.size() - 2)
.forEach(System.out::println);
}
@Test
public void test05() {
//4.获取全班数学的平均成绩
//将流中的以恶搞个学生对象映射成每个学生对应的数学成绩
double avgScore = students.stream().mapToDouble(stu -> stu.getMathScore()).average().getAsDouble();
System.out.println(avgScore);
}
@Test
public void test06() {
// 5.获取全班语文成绩(不包含重复成绩)
// 需要使用mapToDouble
//students.stream().mapToDouble(stu->stu.getChineseScore()).distinct().forEach(System.out::println);
//students.stream().map(stu->stu.getChineseScore()).distinct().forEach(System.out::println);
students.stream().map(Student::getChineseScore).distinct().forEach(System.out::println);
}
@Test
public void test07() {
// 6.将语文成绩或数学成绩在[80,90]之间的学生的姓名收集到一个集合中
//a.语文成绩在[80,90]之间的学生(Predicate) 或者 数学成绩在[80,90]之间(Predicate)
//b.将过滤后的一个个学生对象映射成一个个学生姓名
//c.将过滤和映射中间操作后的数据收集到以恶搞集合中
Predicate<Student>p1=stu->stu.getChineseScore()>=80&&stu.getChineseScore()<=90;
Predicate<Student>p2=stu->stu.getMathScore()>=80&&stu.getMathScore()<=90;
List<String> names = students.stream()
.filter(p1.or(p2))
.map(Student::getName)
.collect(Collectors.toList());
System.out.println(names);
}
}
3.进行一次最终操作获取最终结果
/*
Stream流的最终操作:
1.迭代
forEach:逐个消费流中的元素
2.统计
count:统计流中元素的个数
max :按照一定比较规则(Comparator接口实现规则),来获取流中最大元素
min :按照一定比较规则(Comparator接口实现规则),来获取流中最小元素
3.查找
findFirst
4.匹配
allMatch:只有流中所有的元素都满足Predicate(条件),allMatch方法才返回true,否则返回false
anyMatch:只有流中有一个元素满足Predicate(条件),anyMatch方法才返回true,否则返回false
noneMatch:只有流中所有的元素都不满足Predicate(条件),noneMatch方法才返回true,否则返回false
5.收集
collect:我们可以将最终操作结果收集到一个集合(List,Set,Map)
我们主要通过Collections.toList(),Collections.toSet(),Collections.toMap(),将最终操作结果收集到不同集合中
中间操作:
sorted
*/
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
Stream流的最终操作:
1.迭代
forEach:逐个消费流中的元素
2.统计
count:统计流中元素的个数
max :按照一定比较规则(Comparator接口实现规则),来获取流中最大元素
min :按照一定比较规则(Comparator接口实现规则),来获取流中最小元素
3.查找
findFirst
4.匹配
allMatch:只有流中所有的元素都满足Predicate(条件),allMatch方法才返回true,否则返回false
anyMatch:只有流中有一个元素满足Predicate(条件),anyMatch方法才返回true,否则返回false
noneMatch:只有流中所有的元素都不满足Predicate(条件),noneMatch方法才返回true,否则返回false
5.收集
collect:我们可以将最终操作结果收集到一个集合(List,Set,Map)
我们主要通过Collections.toList(),Collections.toSet(),Collections.toMap(),将最终操作结果收集到不同集合中
中间操作:
sorted
*/
public class StreamDemo03 {
List<String> list = Arrays.asList("zhangsan", "lisi", "laowang");
@Test
public void test01() {
//list.stream().forEach(str-> System.out.println(str));
list.stream().forEach(System.out::println);
}
@Test
public void test02() {
long count = list.stream().count();
System.out.println(count);
}
@Test
public void test03() {
list.stream().sorted().forEach(System.out::println);//字符串的默认排序方式是字典顺序
System.out.println("------------");
/*
Comparator接口的
int compare(T o1, T o2);
如果compare方法返回一个正数,默认为o1>o2
如果compare方法返回一个负数,默认为o1<o2
如果compare方法返回0,默认为o1=o2
sorted方法默认按照元素从小到大排序
比较流程:
str1="lisi"
str2="zhangsan"
str1.length() - str2.length()<0 => "lisi"<"zhangsan"
第二种情况:str2.length() - str1.length() >0 =>"lisi">"zhangsan"
str1="laowang"
str2="zhangsan"
str1.lemgth() - str2.length() => "laowang"<"zhangsan"
第二种情况: str2.length() - str1.length()>0 =>"laowang">"zhangsan"
str1="laowang"
str2="lisi"
str1.length() - str2.length() => "laiwang">"lisi"
第二种情况: str2.length() - str1.length()<0 => "laowang"<"kisi"
最终结果: list<laowang<zhangsan
第二种情况最终结果: zhangsan<laowang<lisi
*/
list.stream().sorted((str1, str2) -> str1.length() - str2.length()).forEach(System.out::println);
System.out.println("-------------------");
list.stream().sorted((str1, str2) -> str2.length() - str1.length()).forEach(System.out::println);
}
//List<String> list = Arrays.asList("zhangsan", "lisi", "laowang");
@Test
public void test04() {
//获取最大长度的字符串
System.out.println(list.stream().max((str1, str2) -> str1.length() - str2.length()).get());
//获取最小长度字符串
System.out.println(list.stream().min((str1, str2) -> str1.length() - str2.length()).get());
}
@Test
public void test05() {
System.out.println(list.stream().findFirst().get());
}
@Test
public void test06() {
System.out.println(list.stream().allMatch(str -> str.length() > 4));//false
System.out.println(list.stream().anyMatch(str -> str.length() > 4));//true
System.out.println(list.stream().noneMatch(str -> str.length() > 4));//true
}
@Test
public void test07() {
Stream<String> stream = list.stream();
List<String> l = stream.collect(Collectors.toList());//将流中的数据收集到List集合中
System.out.println(l.getClass());
System.out.println(l.size());
}
@Test
public void test08() {
Set<String> set = list.stream().collect(Collectors.toSet());
System.out.println(set);
}
@Test
public void test09() {
//将字符串的长度作为ley,字符串的值作为value去构造一个map
Map<Integer, String> map = list.stream().collect(Collectors.toMap(str -> str.length(), str -> str));
System.out.println(map);
}
}