Lambda表达式
题一:
调用Collections.sort()方法,通过定值排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda作为参数传递
分析: 1.定制排序:指自定义比较器|定制排序
自然排序:内部比较器|自然排序
2.先比较年龄,年龄相同才比较姓名
总结: 想要参数实参为lambda表达式,形参就必须为一个函数式接口作为形参 , lambda-> 行为当做参数传递
public class TestLambda001 {
public static void main(String[] args) {
List<Employee>list=new ArrayList<>();
list.add(new Employee("zhangsan",25,8000));
list.add(new Employee("lisi",25,26000));
list.add(new Employee("wangwu",24,20000));
System.out.println(list);
//根据年龄做升序排序,如果年龄相同根据姓名做升序排序
Collections.sort(list,(x,y)-> {
if (x.getAge() == y.getAge()) {
return x.getName().compareTo(y.getName());
}
return Integer.compare(x.getAge(), y.getAge());
});
System.out.println(list);
}
}
题二:
1)声明函数式接口,接口中声明抽象方法,public String getValue(String str)
2)声明类 TestLambda,类中编写方法使用接口作为参数,讲一个字符串转成大写,并作为方法的返回值
3)再将一个字符串的第2个和第4个索引位置进行截取子串
Handler处理器,处理者
public class TestLambda002 {
public static void main(String[] args) {
System.out.println(strHandler("sadasdavewfasdq",s->s.substring(2,7)));
System.out.println(strHandler("sadasdavewfasdq",s->s.toUpperCase()));
System.out.println(strHandler(" dqwdsvsd ",s->s.trim()));
}
//能对一个字符串进行进一步加工处理,返回结果
public static String strHandler(String str,MyFunction my){
return my.getValue(str);
}
}
@FunctionalInterface
interface MyFunction{
public String getValue(String str);
}
题三:
1)声明一个带两个泛型的函数式接口,发型类型为<T,R> T为参数,R为返回值
2)接口中声明对应抽象方法
3)在TestLambda类中声明方法,参数三个,两个long类型的参数,接口作为参数,接口实现中计算两个long型参数的和
4)再计算两个long型参数的乘积
public class TestLambda003 {
public static void main(String[] args) {
System.out.println(testLong(100L,200L,(l1,l2)->l1+l2));
System.out.println(testLong(100L,200L,(l1,l2)->l1*l2));
}
public static Long testLong(Long l1,Long l2,MyFunction2<Long,Long> my){
return my.test(l1,l2);
}
}
interface MyFunction2<T,R>{
public R test(T t1,T t2);
}
Functional
四大内置函数式接口: java.util.function
1.Consumer 消费型接口
void accept(T t) ,对给定参数执行此操作,没有返回值
default Consumer < T > andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然 后执行after操作
2.Function<T,R> 函数型接口
R apply(T t),将此函数应用于给定的参数
3.Supplier 供给型接口
T get(),不需要参数,返回一个由Lambda表达式实现的一个值
4.Predicate 段言型接口
boolean test(T t),对给定的参数进行判断,返回一个bool值
public class Class001_Functional {
public static void main(String[] args) {
testComsumer(2000,m-> System.out.println("每天固定给女主播刷超级火箭"+m));
testComsumer(500,m-> System.out.println("每天做脸消费"+m));
System.out.println(strHandler("nihaoa ",s-> s.trim()));
System.out.println(strHandler("nihaoa ",s-> s.toUpperCase()));
System.out.println(testSupplier(5,()->(int)(Math.random()*(5-1+1)+1)));
System.out.println(testSupplier(46,()->(int)(Math.random()*(20-10+1)+10)));
System.out.println(testPredicate(List.of("abc","abcd","abcde"),s->s.length()>3));
}
//对集合中的多个字符串进行某种规则的过滤,返回满足条件的字符串
public static List<String> testPredicate(List<String> list, Predicate<String> pre){
List<String> newList = new ArrayList<>(); //存放满足条件的字符串
for(String str:list){
if(pre.test(str)){
newList.add(str);
}
}
return newList;
}
//生成指定个数的不同规则的整数
public static List<Integer> testSupplier(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>(); //存放生成的所有整数
for(int i=1;i<=num;i++){
list.add(sup.get());
}
return list;
}
//对字符串进行某种行为处理,返回结果
public static String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
//每天固定消费某些金额做某些行为
public static void testComsumer(double money, Consumer<Double> com){
com.accept(money);
}
}
方法引用
-
方法引用::
简化lambda表达式
是lambda表达式的另外一种表现形式 -
使用前提:
当lambda表达式的lambda体中的实现已经存在另外一个方法实现了,只需要在lambda体中调用另一个方法—> 可以通过方法引用的写法直接引用那个方法
lambda表达式重写的抽象方法的参数列表与返回值对应内部所引用方法的参数列表与返回值
lambda返回值与内部所调用方法的方法直接对应,lambda的参数列表的第一个参数作为内部调用成员方法的对象存在,lambda的第二到多个参数直接匹配内部所调用方法的参数列表存在 -
分类
对象::成员方法
要求: lambda表达式重写的抽象方法的参数列表与返回值对应内部所引用方法的参数列表与返回值
类名::静态方法
lambda表达式重写的抽象方法的参数列表与返回值对应内部所引用方法的参数列表与返回值
类名::成员方法
lambda返回值与内部所调用方法的方法直接对应,lambda的参数列表的第一个参数作为内部调用成 员方法的对象存在,lambda的第二到多个参数直接匹配内部所调用方法的参数列表存在 -
//quite,相当的
考虑是否能通过方法引用简化:
1.Lambda体的实现是否通过调用另一个方法实现的
2.考虑函数接口的参数列表与返回值是否对应内部引用Println方法的参数列表与返回值
public class Class002_Quite {
public static void main(String[] args) {
//对象::成员方法
PrintStream ps = System.out;
Consumer<Integer> com = i-> ps.println(i);
//考虑是否可以通过方法引用简化 : 1)lambda体的实现是否是通过调用另外一个方法实现的--> √ println 2)考虑Consumer中的抽象方法的参数列表与返回值是否对应内部引用println方法的参数列表与返回值--> √
com = ps::println;
com = System.out::println;
//List.of(1,2,3,4,5).forEach(com);
List.of(1,2,3,4,5).forEach(System.out::println);
//类名::静态方法
//求两个小数中的最大值
BiFunction<Double,Double,Double> fun = (x,y)->Math.max(x,y);
//分析是否可以通过方法引用简化: 1)lambda体的实现是否是通过调用另外一个方法实现的--> √ max 2)apply方法的参数列表与返回值是否直接匹配内部所调用方法的参数列表与返回值 -> √
fun = Math::max;
System.out.println(fun.apply(2.1,1.8));;
BiPredicate<String,String> pre = (x,y)->x.equals(y);
//分析是否可以通过方法引用简化: 1)lambda体的实现是否是通过调用另外一个方法实现的-->√ equals
// 2)lambda返回值与内部所调用方法的方法直接对应,lambda的参数列表的第一个参数作为内部调用成员方法的对象存在,lambda的第二到多个参数直接匹配内部所调用方法的参数列表存在 --> √ 可以使用类名::成员方法名简化
pre = String::equals;
System.out.println(pre.test("nihao","nihao"));;
}
}
Stream
Stream :
关注流式运算,不是传输与存储
io流关注数据的传输
集合与数组关注数据的存储
注意😗*
1.Stream是一次性的流,一旦使用过就不能重复使用
2.Stream的操作不会影响数据源中的数据
3.延迟执行|惰性加载: 当获取终止行为时候才会执行中间操作
使用步骤:
1.获取Stream流
2.中间行为 : 一系列的流式操作
3.终止行为
创建Stream的方式:
1.Collection Stream stream()
2.Arrays stream()
3.Stream.of(值列表)
public class Class001_Stream {
public static void main(String[] args) {
//1..Collection Stream<E> stream()
List<Integer> list = List.of(1,2,3,4,5);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);
//2.Arrays stream()
String[] arr = {"abc","bbb","ccc"};
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(System.out::println);
//3.Stream.of(值列表)
Stream<Integer> stream2 = Stream.of(3,2,1);
stream2.forEach(System.out::println);
}
}
流式中间操作
流式中间操作
1.过滤 Stream filter(Predicate<? super T> predicate);
2.去重 Stream distinct()
3.截取 Stream limit(long maxSize)
4.跳过 Stream skip(long)
5.排序 sorted() | sorted(Comparator<? super T> comparator)
6.映射 map(Function) :接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元 素。
注意: 中间操作都会返回一个持有结果的新的流
流操作是每一条从头到尾单独操作,并不是所有数据统一进入操作
public class Class002_Stream {
static List<Employee> list = Arrays.asList(
new Employee("lisi",19,5000),
new Employee("wangwu",18,4000),
new Employee("tianqi",17,4000),
new Employee("zhaoliu",20,3000),
new Employee("zhangsan",20,6000),
new Employee("zhangsan",20,6000)
);
public static void main(String[] args) {
//1.获取一个stream
Stream<Employee> stream = list.stream();
//2.中间操作 延迟执行
/*stream = stream.filter(e->{
System.out.println("--------------过滤-----------");
return e.getAge()>=18;
}).distinct()
.limit(3)
.skip(1)
.filter(e->{
System.out.println("-----------最终过滤------------"+e);
return true;
});*/
//排序
//stream = list.stream().sorted();
// stream = list.stream().sorted((x,y)- >Double.compare(y.getSalary(),x.getSalary()));
//映射
//Stream<Double> stream2 = list.stream().map(e->e.getSalary());
Stream<Double> stream2 = list.stream().map(Employee::getSalary);
//3.终止行为
stream2.forEach(System.out::println);
}
}
public class Class003_Stream {
static List<Employee> list = Arrays.asList(
new Employee("lisi",19,5000),
new Employee("wangwu",18,4000),
new Employee("tianqi",17,4000),
new Employee("zhaoliu",20,3000),
new Employee("zhangsan",20,6000),
new Employee("zhangsan",20,6000)
);
public static void main(String[] args) {
//1.获取一个stream
Stream<Employee> stream = list.stream();
//2.中间操作,终止行为
//anyMatch-检查是否至少匹配一个元素
System.out.println( stream.allMatch(e->e.getAge()>=18));;
//需求:按工资排序,获取第一个员工信息
// findFirst-返回第一个元素
//1)降序排序 2)找到第一个元素
Optional<Employee> op1= list.stream().sorted((x, y)->Double.compare(y.getSalary(),x.getSalary()))
.findFirst();
if(op1.isPresent()){
System.out.println(op1.get());
}
//并行流
op1 = list.parallelStream().findAny();
System.out.println(op1.get());
//薪资>5000的员工个数
// count-返回流中元素的总个数
System.out.println(list.stream().filter(e->e.getSalary()>5000).count());
max-返回流中最大值
min-返回流中最小值
System.out.println(list.stream().max((x,y)->Double.compare(x.getSalary(),y.getSalary())).get());
//规约 map-reduce 先加工->后处理汇总结果
System.out.println(list.stream().map(Employee::getSalary).reduce((x,y)->x+y).get());;
System.out.println(Stream.of(1,2,3,4,5).reduce((x,y)->{
System.out.println("========>x = "+ x + " , y ="+y );
return x+y;
}).get());;
System.out.println(Stream.of(1,2,3,4,5).reduce(100,(x,y)->{
System.out.println("========>x = "+ x + " , y ="+y );
return x+y;
}));
// 收集(collect)
//collect 主要依赖 java.util.stream.Collectors 类内置的静态方法。
//Collectors.toList()
List<String> names = list.stream().distinct().map(Employee::getName).collect(Collectors.toList());
System.out.println(names);
Set<String> names2 = list.stream().map(Employee::getName).collect(Collectors.toSet());
System.out.println();
Map<String,Double> map = list.stream().distinct().collect(Collectors.toMap(Employee::getName,Employee::getSalary));
System.out.println(map);
}
}
多线程
**线程:**执行的顺序流
**多线程:**多条执行路径,多任务执行,如果没有多任务,多线程没有意义
**线程与进程:**进程:一个操作系统中的多个程序
进程包括1~n个线程
每个进程都有自己的代码和数据空间
资源分配的最小单位
进程间的切换会有比较大的开销
**线程:**一个程序中的多个顺序流
多个线程之间共享进程的代码和数据空间
每个线程存在自己的运行栈和程序计数器
调度和执行的最小单位
线程切换的开销小
**优点:**资源利用率更好,程序设计在某些情况下更简单,程序响应更快
**线程三高:**1.高可用
2.高性能
3.高并发
**线程的创建:**1.继承Thread类,重写run方法,在run方法中定义线程体 +start()
2.实现Runnable接口,重写run方法+start()–>简单,接口 可以多实现,实现资源共享
3.juc包下Callable接口,重写call(),在call方法中定义线程 体+线程池
public class Class001_thread extends Thread{
/*
线程体
*/
public void run(){
for(int i=1;i<20;i++){
System.out.println("1");
try {
Thread.sleep(5);
}catch (InterruptedException e){
e.printStackTrace();
//printStackTrace 在命令行打印异常信息在程序中出错的位置及原因
}
}
}
public static void main(String[] args) {
//创建线程
Class001_thread td=new Class001_thread();
//开启线程 void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法。
td.start();
for (int i=1;i<20;i++){
System.out.println("0");
try {
Thread.sleep(5);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}