1.lambda表达式
前提:必须是函数式接口
特殊的匿名内部类,语法更简洁
允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递
语法:
<函数式接口><变量名>=(参数1,参数2...)->{
方法体
};
注意:
函数式接口:接口中只有一个抽象方法。
(参数1,参数2):抽象方法的参数
->: 分隔符
{}:表示抽象方法的实现
java">package com.ghx;/*** @author :guo* @date :Created in 2025/2/28 17:09* @description:* @version:*/
public class Test01 {public static void main(String[] args) {//该构造方法需要传递一个任务对象,Runnable类型My my=new My();Thread t1=new Thread(my);t1.start();//匿名内部类Runnable task=new Runnable() {@Overridepublic void run() {System.out.println("bbbbb");}};Thread t2=new Thread(task);t2.start();}
}
class My implements Runnable{@Overridepublic void run() {System.out.println("aaaaaaaaaaaaaaaaaaaaa");}
}
Thread 类需要 Runnable 接口作为参数,其中的抽象run 方法是用来指定线程任务内容的核
心
为了指定 run 的方法体,不得不需要 Runnable 接口的实现类
为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类
必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不
能写错
而实际上,似乎只有方法体才是关键所在。
可以使用lambda表达式
//lambda表达式 Runnable task2=()->{System.out.println("使用lambda表达式"); }; Thread t3=new Thread(task2); t3.start();
1.1无参的
java">package com.ghx.demo;/*** @author :guo* @date :Created in 2025/2/28 17:19* @description:* @version:*/
public class Test02 {public static void main(String[] args) {//匿名内部类Swim s=new Swim() {@Overridepublic void swimming() {System.out.println("使用匿名内部类");}};fun(s);/*Swim s2=()->{System.out.println("使用lambda表达式");};fun(s2);*/fun(()->{System.out.println("使用lambda表达式");});}public static void fun(Swim s){s.swimming();}
}
interface Swim{void swimming();
}
1.2有参的
java">package com.ghx.demo02;import java.util.*;/*** @author :guo* @date :Created in 2025/2/28 17:25* @description:* @version:*/
public class Test03 {public static void main(String[] args) {List<Person> personList=new ArrayList<>();personList.add(new Person("张三",18,180));personList.add(new Person("李四",19,190));personList.add(new Person("王五",20,170));personList.add(new Person("赵六",21,185));//按年龄从大到小排/* Comparator<Person> comparator=new Comparator<Person>() {//int: 0表示新添的元素和集合原本的相同@Overridepublic int compare(Person o1, Person o2) {return o2.getAge()-o1.getAge();}};Collections.sort(personList,comparator);for (Person person : personList) {System.out.println(person);}*/System.out.println("-------------------------------------------------------------------------");Comparator<Person> comparator1=(Person o1, Person o2)->{return o2.getAge()-o1.getAge();};Collections.sort(personList,comparator1);for (Person person : personList) {System.out.println(person);}}
}
class Person{private String name;private int age;private int height;public Person() {}public Person(String name, int age, int height) {this.name = name;this.age = age;this.height = height;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}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;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}
}
1.3特点
Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
·左侧:(参数1,参数2…)表示参数列表
·右侧:{}内部是方法体
注意事项
·形参列表的数据类型会自动推断,即可以省略参数类型
如果形参列表为空,只需保留()
如果形参只有1个,()可以省略,只需要参数的名称即可public class Test02 {public static void main(String[] args) {Swim swim=n->{System.out.println("使用lambda表达式"+n);};fun(swim);}public static void fun(Swim s){s.swimming("aa");} } interface Swim{void swimming(String name); }
如果执行语句只有一句,且无返回值,(可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句Comparator<Person> comparator1=( o1, o2)->o2.getAge()-o1.getAge();
·Lambda不会生成一个单独的内部类文件
2.函数式接口
如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
@Functionallnterface 注解检测接口是否符合函数式接口
java">package com.ghx.demo03;/*** @author :guo* @date :Created in 2025/2/28 18:43* @description:* @version:*/
public class Test03 {public static void main(String[] args) {MyInterface m=arr -> {int sum=0;for (int i : arr) {sum+=i;}System.out.println("数组的和为:"+sum);};fun(m);}public static void fun(MyInterface myInterface){int[] arr={1,2,3,4,5,6,7,8,9,10};myInterface.getSum(arr);}
}
@FunctionalInterface
interface MyInterface {//求数组的和public abstract void getSum(int[] arr);
}
分析
我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽 象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。
常见的函数式接口
java.util.function保存
2.1Consumer<T>
有参无返回值
java">package com.ghx.demo04;import java.util.function.Consumer;/*** @author :guo* @date :Created in 2025/2/28 18:53* @description:* @version:*/
public class Test04 {public static void main(String[] args) {Consumer<Double> c=t->{System.out.println("消费了"+t+"元");};fun1(c,100);}// 消费型接口,当调用某个方法时,该方法需要的参数为接口类型,应该想到使用lambda表达式public static void fun1(Consumer<Double> consumer,double money){consumer.accept(money);}
}
2.2supplier供给型函数式接口
无参,有返回结果的函数式接口
T get();
java">package com.ghx.demo05;import java.util.Random;
import java.util.function.Supplier;/*** @author :guo* @date :Created in 2025/2/28 18:58* @description:* @version:*/
public class Test05 {public static void main(String[] args) {fun(()->new Random().nextInt(10));}public static void fun(Supplier<Integer> supplier){Integer i=supplier.get();System.out.println(i);}
}
2.3Function<T,R>函数型函数式接口
T:参数类型的泛型
R:函数返回结果的泛型
有参,有返回值
java">package com.ghx.demo06;import java.util.function.Function;/*** @author :guo* @date :Created in 2025/2/28 19:04* @description:* @version:*/
public class Test06 {public static void main(String[] args) {fun((t)->{return t.toUpperCase();},"hello world");}public static void fun(Function<String,String> function,String msg){String apply = function.apply(msg);System.out.println(apply);}
}
2.4Predicated<T>断言型
当传入一个参数时,需要对该参数进行判断时,需要这种函数
java">package com.ghx.demo07;import java.util.function.Predicate;/*** @author :guo* @date :Created in 2025/2/28 19:09* @description:* @version:*/
public class Test07 {public static void main(String[] args) {fun(n->{return n.length()>3?true:false;},"东方铁心");}public static void fun(Predicate<String> predicate,String name){boolean b = predicate.test(name);System.out.println(b);}
}
3.方法引用
3.1lambda表达式的冗余
java">package com.ghx.demo07;import java.util.function.Consumer;/*** @author :guo* @date :Created in 2025/2/28 19:14* @description:* @version:*/
public class Test01 {public static void main(String[] args) {Consumer<Integer[]> c=arr->{int sum=0;for (Integer i : arr) {sum+=i;}System.out.println("数组的和为:"+sum);};fun(c);}public static void fun(Consumer<Integer[]> consumer){Integer[] arr=new Integer[]{1,2,3,4,5,6,7,8,9,10};consumer.accept(arr);}public static void sum(Integer[] arr){int sum=0;for (Integer i : arr) {sum+=i;}System.out.println("数组的和为:"+sum);}
}
如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻
辑?可以直接“引 用“过去就好了:…--方法引用。
java">package com.ghx.demo07;import java.util.function.Consumer;/*** @author :guo* @date :Created in 2025/2/28 19:14* @description:* @version:*/
public class Test01 {public static void main(String[] args) {/* Consumer<Integer[]> c=arr->{int sum=0;for (Integer i : arr) {sum+=i;}System.out.println("数组的和为:"+sum);};fun(c);*/Consumer<Integer[]> c=Test01::sum;fun(c);}public static void fun(Consumer<Integer[]> consumer){Integer[] arr=new Integer[]{1,2,3,4,5,6,7,8,9,10};consumer.accept(arr);}public static void sum(Integer[] arr){int sum=0;for (Integer i : arr) {sum+=i;}System.out.println("数组的和为:"+sum);}
}
::写法,被称为“方法引用”,是一种新的语法
3.2静态方法引用
java">package com.ghx.demo08;import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;/*** @author :guo* @date :Created in 2025/2/28 19:22* @description:* @version:*/
public class Test01 {public static void main(String[] args) {List<Integer> list=new ArrayList<>();list.add(18);list.add(22);list.add(3);list.add(4);//int compare=(T o1,T o2);//Comparator<Integer> c=(o1, o2)->o1-o2;// Comparator<Integer> c=(o1, o2)->Integer.compare(o1,o2);Comparator<Integer> c=Integer::compare;list.sort(c);System.out.println(list);}
}
java">package com.ghx.demo08;import java.util.Arrays;
import java.util.Comparator;/*** @author :guo* @date :Created in 2025/2/28 19:30* @description:* @version:*/
public class Test02 {public static void main(String[] args) {Person[] ps=new Person[4];ps[0]=new Person("张三",25);ps[1]=new Person("李四",19);ps[2]=new Person("王五",15);ps[3]=new Person("赵六",21);
// Comparator<Person> c=(o1, o2)->o1.getAge()-o2.getAge();
// Comparator<Person> c=(o1, o2)->Person.compareTo(o1,o2);
// Comparator<Person> c=Person::compareTo;Arrays.sort(ps,Person::compareTo);for (Person person : ps) {System.out.println(person);}}
}
class Person{private String name;private int age;public static int compareTo(Person p1,Person p2){return p1.getAge()-p2.getAge();}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public Person() {}public Person(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;}
}
3.3实例方法引用
实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用。
java">package com.ghx.demo08;import java.util.function.Supplier;/*** @author :guo* @date :Created in 2025/2/28 19:37* @description:* @version:*/
public class Test03 {public static void main(String[] args) {Person2 p1=new Person2("张三",25);
// Supplier<String> s=()->p1.getName();//lambda表达式中只有一条语句,而且又调用了某个方法Supplier<String> s=p1::getName;/*这样就不能使用Supplier<String> s1=()->{System.out.println("++++");return p1.getName();};*/fun(s);}public static void fun(Supplier<String> supplier){String s = supplier.get();System.out.println(s);}
}
class Person2{private String name;private int age;public static int compareTo(Person p1,Person p2){return p1.getAge()-p2.getAge();}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public Person2() {}public Person2(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;}
}
3.4对象方法引用
java">package com.ghx.demo08;import java.util.function.BiFunction;
import java.util.function.Function;/*** @author :guo* @date :Created in 2025/2/28 19:49* @description:* @version:*/
public class Test04 {public static void main(String[] args) {
// Function<String,Integer> function=(str)->{
// return str.length();
// };Function<String,Integer> function=String::length;System.out.println(function.apply("hello world"));/*BiFunction<String,String,Boolean> biFunction=(str1,str2)->{return str1.equals(str2);};*/BiFunction<String,String,Boolean> biFunction=String::equals;System.out.println(biFunction.apply("hello", "world"));}
}
3.5构造方法引用
java">package com.ghx.demo08;import java.util.function.Function;
import java.util.function.Supplier;/*** @author :guo* @date :Created in 2025/2/28 19:57* @description:* @version:*/
public class Test05 {public static void main(String[] args) {
// 构造方法引用: 类名::new (参数)->new 类名(参数)/*Supplier<String> s=()->{return new String("hello");};*//* Supplier<Teacher> s=()->{return new Teacher("张三");};*/// Supplier<Teacher> s=Teacher::new;//调的无参的//调有参的
// Function<String,Teacher> s=(n)->new Teacher(n);Function<String,Teacher> s=Teacher::new;Teacher s1 = s.apply("张三");
// Teacher s1 = s.get();System.out.println(s1);}
}
class Teacher{private String name;public Teacher(String name) {this.name = name;}public Teacher() {}@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
4.Stream流
Java8的两个重大改变,一个是Lambda表达式,另一个就是Stream AP!表达式。
Stream是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的査找、过滤、筛选等操作
4.1为什么使用Stream流
对集合的操作语法简洁,性能比传统快
当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。
需求如下:
一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰
1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
java">package com.ghx.demo;import java.util.ArrayList;
import java.util.Collections;/*** @author :guo* @date :Created in 2025/2/28 20:09* @description:* @version:*/
public class Test01 {public static void main(String[] args) {ArrayList<String> list=new ArrayList<>();Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");list.stream().filter((item)->item.startsWith("张"))
// .filter((item)->item.length()==3).forEach((item)-> System.out.println(item));}
}
4.2Stream流的原理
Stream流式思想类似于工厂车间的“生产流水线",Stream流不是一种数据结构,不保存数据,而是
对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream流不保存数据,只对数据进行加工处理
4.3如何获取Stream流对象
通过Collection对象的stream()或parallelStream()方法
通过Arrays类的stream()方法
通过Stream接口的of()、iterate()、generate()方法
通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法
获取串行流
java">package com.ghx.demo09;import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;/*** @author :guo* @date :Created in 2025/2/28 20:20* @description:* @version:*/
public class Test01 {public static void main(String[] args) {//通过集合对象调用Stream()获取流List<String> list=new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");Stream<String> stream = list.stream();//通过Arrays数组工具类获取Stream对象int[] arr={1,2,3,4,5,6,7,8,9,10};IntStream stream1 = IntStream.of(arr);//使用Stream类中的of方法Stream<String> stream2 = Stream.of("hello", "world", "java");//LongStreamLongStream longStream=LongStream.range(1,10);}
}
获取并行流
//通过集合对象调用Stream()获取流 List<String> list=new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王五"); list.add("赵六"); //并行流 Stream<String> stringStream = list.parallelStream(); //stringStream.forEach(i-> System.out.println(i));stringStream.forEach(System.out::println);
4.4常见的api
java">package com.ghx.demo09;import java.util.ArrayList;
import java.util.List;/*** @author :guo* @date :Created in 2025/2/28 20:32* @description:* @version:*/
public class Test02 {public static void main(String[] args) {List<Person> personList = new ArrayList<>();personList.add(new Person("欧阳雪",18,"中国",'F'));personList.add(new Person("Tom",24,"美国",'M'));personList.add(new Person("Harley",22,"英围",'F'));personList.add(new Person("向天笑",20,"中国",'M'));personList.add(new Person("李康",22,"中国",'M'));personList.add(new Person("小梅",20,"中国",'F'));personList.add(new Person("何雪",21,"中国",'F'));personList.add(new Person("李康",22,"中国",'M'));//找出年龄大于18的,filter()过滤器需要一个断言接口函数,断言接口返回true,获取该元素。 foreach(Consumer)//无论执行多少个中间操作,如果没有执行终止操作,那么中间操作都不会执行personList.stream().filter(p->p.getAge()>18).forEach(System.out::println);//找出中国人的数量long count = personList.stream().filter(p -> p.getCountry().equals("中国")).count();System.out.println(count);}
}
class Person{private String name;private int age;private String country;private char sex;public Person(String name, int age, String country, char sex) {this.name = name;this.age = age;this.country = country;this.sex = sex;}public Person() {}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", country='" + country + '\'' +", sex=" + sex +'}';}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;}public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}
}
//集合中每个元素只要名map,原来流中的每个元素转为另一种格式 personList.stream().map(p->{Map<String,Object> n=new HashMap<>();n.put("name",p.getName());n.put("age",p.getAge());return n;}).forEach(System.out::println);
//对流中元素排序 personList.stream().sorted((o1,o2)-> o1.getAge()- o2.getAge()).forEach(System.out::println);
//查找年龄最大的,max终止操作 Optional<Person> max = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge()); System.out.println(max.get());
//规约,求集合中所有的年龄和,参数和返回类型必须一致 Optional<Integer> reduce = personList.stream().map(p -> p.getAge()).reduce((a, b) -> a + b); System.out.println(reduce.get());//在上面的基础上加了10
Integer reduce2 = personList.stream().map(p -> p.getAge()).reduce(10, (a, b) -> a + b); System.out.println(reduce2);
//搜集方法 collect 终止方法 //年龄大于20性别为M List<Person> collect = personList.stream().filter(p -> p.getAge() > 20 && p.getSex() == 'M').collect(Collectors.toList()); System.out.println(collect);
Optional<Person> first = personList.stream().filter(item -> item.getSex() == 'F').findFirst(); System.out.println(first.get()); //并行流 Optional<Person> any = personList.parallelStream().filter(p -> p.getSex() == 'F').findAny(); System.out.println(any.get());
//都符合才是true boolean b = personList.parallelStream().filter(p -> p.getAge() > 18 && p.getSex() == 'F').allMatch(p -> p.getAge() > 20 ); System.out.println(b);