JDK新特性
函数式接口
1.说说JDK中函数式接口家族?
Function入参-1 返回值-1
– BiFunction入参-2返回值-1(两个入参,两个返回值B->Binary二进制)
Consumer 消费者入参-1
– BiConsumer
Supplier 提供者返回值-1
Predicate断言入参-1 返回值-布尔类型
双shift进行查找
2.Lambda表达式
使用它的原因:1.不想再单独封装一个新的实现类 2.想获取调用方定义的一些变量,而不想通过传参的方式使用
缺点:重用受限制
转换为Lambda表达式的流程:
1、去掉类型声明和()
2、去掉方法修饰符、返回类型、方法名
3、在参数列表和方法体的左括号之间标记一个"->"
基于上述的简化,还有如下更简洁的写法:
1、参数列表中每一个参数的类型声明都可以去掉
2、如果方法逻辑中只有一行代码,可以把这个方法体的“0”、”; "、“return”
比如:
private static Comparator<User> c = new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getName().compareTo(o2.getName());
}
};
Lamda后:
private static Comparator<User> c = (o1, o2)->o1.getName().compareTo(o2.getName());
3.Lambda的方法引用
静态方法使用类名::方法名
非静态方法使用this::方法名或实例名::方法名
原来:show(users,user-> System.out.println(user));
变换后(输出语句是System.out类的):show(users, System.out::println);
调用的方法:
public static void show(List<User> list, ShowInfo showInfo) {
for (User u : list) {
showInfo.showUser(u);
}
}
lamda实现的接口:
public interface ShowInfo {
void showUser(User user);
}
完成此题:
请声明一个Consumer类型变量,具体的逻辑如下:
1.接收一个集合作为输入参数,然后对集合中的元素进行排序,然后再输出它们的信息.2.使用这个Consumer变量,实例化一个集合,传递给它,让它执行
package com.think.dashazi;
import com.think.lv1.utils.RandomUtils;//这个工具类代码也在下面
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Anonymity {
public static void main(String[] args) {
testConsumerAndSupplier(c0,s0);
}
//Supplier接口的Lambda实现
public static final Supplier<List<User>> s0 = ()->{
List<User> list = new ArrayList<>();
for (int i = 0; i <5 ; i++) {
list.add(new User(RandomUtils.randomString(),RandomUtils.randomNumber(100)));
}
return list;
};
//Consumer接口的Lambda实现
public static final Consumer<List<User>> c0 = (users)->{
// Collections.sort(users, (o1,o2)-> o1.getName().compareTo(o2.getName()));
Collections.sort(users, Comparator.comparing(User::getName));
System.out.println(users);
};
public static void testConsumerAndSupplier(Consumer<List<User>> c,Supplier<List<User>> s){
List<User> list = s.get();//获取
c.accept(list);//把list拿去处理
}
}
package com.think.dashazi;
import java.util.Comparator;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// @Override
// public int compare(User o1, User o2) {
// return o1.getName().compareTo(o2.getName());//正序 1,2,3从小到大
// }
}
RandomUtils工具类
package com.think.lv1.utils;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class RandomUtils {
// Utility 工具
// CTRL + SHIFT + U 批量转换大小写
// static 修饰的内容,是不依赖于这个类的任何实例的,当这个类一旦在运行期间加载进来,它就已经存在,有且只有一份,大家共享的
// static修饰的方法只能访问static修饰的变量
private final static String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; // 字典数据
private static final Random ran = new Random(); // 对于引用类型,只要它自己的地址不发生改变,也可以修饰为final的
// private static final String[] genders = new String[]{"male, female"};
private static final String[] genders = {"male", "female"}; // 利用了编译器的优化机制(语法糖)进行简化,和上面这一行等效
public static void longSleep(int min, int max) {
int time = randomNumber(min, max);
try {
// Thread.sleep(time);
TimeUnit.MILLISECONDS.sleep(time); // 代码易读,语义更清晰
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void longSleep(int sec) {
try {
// Thread.sleep(time);
TimeUnit.MILLISECONDS.sleep(sec); // 代码易读,语义更清晰
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* <p>生成步骤</p>
* <ul>
* <li>对字典字符串拆分,得到一个字符数组</li>
* <li>产生某一个合适范围的索引值</li>
* <li>把字符数组变换成一个完整的字符串</li>
* </ul>
*
* @param len 表示要生成的字符串长度
* @return 返回一个随机内容的字符串
*/
public static String randomString(int len) {
// String[] split = data.split("");
char[] chars = data.toCharArray(); // 'A'
// 循环从split数组中随机获取一个字符,然后组装成一个完整字符串
// 创建一个临时存放零散字符的数组
char[] temp = new char[len]; // 用来构造一个完整的字符串的
for (int j = 0; j < len; j++) {
char c = chars[ran.nextInt(data.length())]; // [0, data.length())
temp[j] = c;
}
return new String(temp); // 不使用字符串的拼串是因为会产生大量的内存零时垃圾
}
public static String randomString() {
return randomString(5); // 重用上面的逻辑
}
/**
* 产生从from到to之间的某一个数字,包左,不包右
*
* @param min 最小值
* @param max 最大值
*/
public static int randomNumber(int min, int max) { // 3 - 10
if (max < min) {
System.out.printf("%d 不能 比 %d 小\r\n", max, min);
}
return ran.nextInt(max - min) + min;
}
/**
* 产生从 1 到to之间的某一个数字,包左,不包右
*
* @param max 最大值
*/
public static int randomNumber(int max) {
return randomNumber(1, max);
}
public static String randomGender() {
// return ran.nextBoolean() ? "male" : "female";
int index = ran.nextInt(2); // 0 1
return genders[index];
// return genders[ran.nextInt(2)];
}
}
流式编程
简单入门:
// 整数流的创建
IntStream stream = Arrays.stream(arr);
stream.forEach(System.out::println);
System.out.println("------------------------------------------");
// 经过上述的逻辑,指针已经指向了数据流的末尾了
stream = Arrays.stream(arr);
// 像是把整个数组,变成了一股由各个元素组成的水流
stream
.filter((item) -> item % 2 == 0) // 使用断言进行过滤
// .limit(5) // 限定最后结果为5个
.forEach(System.out::println);
基本下面都是一些方法的调用
package com.think.lv2.stream;
import com.think.lv1.utils.RandomUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ListDemo {
public static void main(String[] args) {
// Function<Integer, List<User>> fn = (size) -> {
// List<User> users = new ArrayList<>();
// for (int i = 0; i < size; i++) {
// users.add(new User(RandomUtils.randomString(), RandomUtils.randomNumber(100)));
// }
// return users;
// };
//
// List<User> users = fn.apply(20);
//
// // users.stream()
// // // 在此处开了一个小窗口,让你可以在不修改数据的情况下去窥探里面的每一个元素的内容
// // // 一般用于开发人员调试逻辑
// // .peek(u -> System.out.println(u.getAge()))
// // .filter(u -> u.getAge() > 18)
// // .forEach(System.out::println);
//
// // users.stream()
// // // .map( user -> user.getName() )
// // // .map(User::getName)
// // // 一旦使用map进行了类型转换,那么在这个流的后面,就只剩下被转换的内容了
// // // .mapToInt(User::getAge)
// // .sorted(Comparator.comparing(User::getName))
// // .forEach(System.out::println);
//
// // 重新收集符合条件的一个新集合
// List<User> userList = users.stream()
// .filter(user -> user.getAge() >= 18)
// .sorted(Comparator.comparing(User::getName))
// .collect(Collectors.toList());
//
// List<String> nameList = users.stream()
// .map(User::getName)
// .collect(Collectors.toList());
//
// // long count = users.stream().count();
//
// // 该流中只要有一个匹配断言,就为true
// boolean flag = users.stream().anyMatch(user -> user.getAge() >= 18);
//
// users.stream().findFirst();// 找到第一个
// users.stream().findAny(); // 找到任何一个
//
// Optional<User> opt = users.stream().max(Comparator.comparing(User::getAge));
//
// if(opt.isPresent()) { // 找到了符合条件的
// User user = opt.get(); // 去获取它
// System.out.println(user);
// }
testGroup();
}
private static void testGroup() {
Function<Integer, List<User>> fn = (size) -> {
List<User> users = new ArrayList<>();
for (int i = 0; i < size; i++) {
users.add(new User(RandomUtils.randomString(), RandomUtils.randomNumber(100), RandomUtils.randomNumber(4)));
}
return users;
};
List<User> users = fn.apply(30);
// 根据班级来分组,要求得到3个独立的集合或者数组
// Map<Boolean, List<User>> collect = users.stream().collect(Collectors.partitioningBy(user -> user.getAge() >= 18));//只能分成两个组,一个是满足要求的,一个是不满足要求的
// Set<Map.Entry<Boolean, List<User>>> entries = collect.entrySet();
//
// for (Map.Entry<Boolean, List<User>> entry : entries) {
// System.out.println(entry.getKey() + ":" + entry.getValue());
// }
Map<Integer, List<User>> collect = users.stream()
.collect(Collectors.groupingBy(User::getClassNo));
// 根据2个甚至更多个字段来分组(这些字段的值都一样,认为是一组的)
// users.stream().collect(Collectors.groupingBy( user -> user.getA() + user.getB()));
Set<Map.Entry<Integer, List<User>>> entries = collect.entrySet();
for (Map.Entry<Integer, List<User>> entry : entries) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
完成下题:
根据2个班级和年龄甚至更多个字段来分组(提示:这些字段的值都一样,认为是一组的,使用
收集器collect(Collectors.groupingBy(user->user.getAge()>=18)))
users.stream().collect(Collectors.groupingBy( user -> user.getClassNo() + user.getAge()));