Lambda表达式
简化匿名内部类的代码写法(只能简化函数式接口的匿名内部类的写法形式)JDK8.0
首先是接口,其次接口中有且仅有一个抽象方法的形式@FunctionalInterface注释校验
面向对象编程:注重谁来做 函数式编程:注重做什么
Lambda表达式标准格式:(形式参数) -> {代码块}
//匿名内部类写法 goRuning(new Runing() { @Override public void run() { System.out.println("特斯拉飞驰"); } }); //Lambda表达式写法 goRuning(() -> { System.out.println("特斯拉飞驰"); } ); //Lambda表达式简化 goRuning(() -> System.out.println("特斯拉飞驰"));
():里面没有内容,可以看成是方法形参列表为空
->:用箭头指向要做的事情
{ }:代码块,可以看成是方法体中的内容省略规则:
参数类型可以省略,但是有多个参数的情况下,不能只省略一个
如果参数有且仅有一个,那么小括号可以省略
如果代码块的语句只有一条,可以省略大括号和分号,甚至是return
Lambda表达式与匿名内部类的区别
类型:
匿名内部类:接口,抽象类,具体类
Lambda表达式:接口
限制:
匿名内部类:接口可以有一个或者多个抽象方法
Lambda表达式:接口中只能一个抽象方法,可以@FunctionalInterface注释校验
实现原理:
匿名内部类:编译之后,产生一个单独的.class字节码文件
Lambda表达式:对应的字节码文件会在运行时动态生成
常用的函数式接口
Supplier接口(供应者)
java.util.function.Supplier<T>接口
它意味着"供给",对应的Lambda表达式需要对外提供一个符合泛型类型的对象数据
public class DemoSupplier { public static void main(String[] args) { String s1 = "Hello"; String s2 = "World"; //1.匿名内部类的方式 fun(new Supplier<String>() { @Override public String get() { return s1 + s2; } }); System.out.println("---------"); //2.使用lambda表达式的标准格式 fun(() -> { return s1.toLowerCase() + s2.toLowerCase(); }); System.out.println("---------"); //3.使用lambda表达式的简化格式 fun(() -> s1.toUpperCase() + s2.toUpperCase()); } //定义方法使用函数式接口Supplier作为参数 public static void fun(Supplier<String> supplier) { //调用抽象方法get,获取字符串str //至于str的内容是什么以及如何获取,这里说不清楚 String str = supplier.get(); System.out.println(str); } }
Consumer接口(消费者)
java.util.function.Consumer<T>接口
则正好相反,它不是生产一个数据,而是消费一个数据其数据类型由泛型参数决定
public class DemoConsumer { public static void main(String[] args) { String str = "Hello World"; //1.匿名内部类的方式 fun(str, new Consumer<String>() { @Override public void accept(String s) { //按照大写消费 System.out.println(s.toUpperCase()); } }); //2.使用lambda表达式的标准格式 fun(str, (String s) -> { //按照小写消费 System.out.println(s.toLowerCase()); } ); //3.使用lambda表达式的简化格式 fun(str, s -> System.out.println(s.length()));//长度 } //定义方法使用函数式接口Consumer作为参数 public static void fun(String s, Consumer<String> consumer) { //调用抽象方法accept,处理字符串s //如何处理字符串s,说不清 consumer.accept(s); } }
Function接口(转换)
java.util.function.Function<T,R>接口
用来根据一个类型的数据得到另一个类型的数据前者称为前置条件,后者称为后置条件,有进有出转换
public class DemoFunction { public static void main(String[] args) { String sNum = "12345"; //1.匿名内部类的方式 fun(sNum, new Function<String, Integer>() { @Override public Integer apply(String s) { return Integer.parseInt(s); } }); //2.使用lambda表达式的标准格式 fun(sNum, (String s) -> { return Integer.parseInt(s); }); //3.使用lambda表达式的简化格式 fun(sNum, s -> Integer.parseInt(s)); } /* 定义方法,使用函数式接口Function作为参数 */ public static void fun(String strNum, Function<String, Integer> function) { //根据方法参数String类型的strNum //获取int数字num,至于如何根据String类型的strNum获取int数字num说不清 int num = function.apply(strNum); System.out.println(num); } }
Predicate接口(判断)
java.util.function.Predicate<T>接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用
public class DemoPredicate { public static void main(String[] args) { String ss = "HelloWorld"; //1.匿名内部类的方式 fun(ss, new Predicate<String>() { @Override public boolean test(String s) { //判断字符串长度是否大于5 return s.length() > 5; } }); //2.使用lambda表达式的标准格式 fun(ss,(String s)->{ //判断字符串是否包含"H" return s.contains("H"); }); //3.使用lambda表达式的简化格式 fun(ss, s -> s.contains("h")); } /* 定义方法,使用函数式接口Predicate作为参数 */ public static void fun(String str, Predicate<String> predicate) { //调用抽象方法test,根据字符串ss,获取boolean结果 //至于根据字符串ss,如何获取boolean结果,说不清 boolean result = predicate.test(str); System.out.println(result); } }
Stream流
JDK8,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念
目的:用于简化集合和数组操作的API
获取Stream流:
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法:
流水线上的操作,一次操作完毕之后,还可以继续进行其他操作
终结方法:
一个Steam流只能有一个终结方法,是流水线上的最后一个操作
创建Stream流
Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能
集合获取Stream流的方式
可以使用Collection接口中默认方法stream()生产流
数组获取Stream流的方式
public class DemoGetStream { public static void main(String[] args) { //1.获取List集合对象对应的Stream流对象 List<String> list = new ArrayList<>(); Stream<String> s1 = list.stream(); //2.获取Set集合对象对应的Stream流对象 Set<String> set = new HashSet<>(); Stream<String> s2 = set.stream(); //Map集合,内部没有直接定义stream方法获取Stream流对象 //必须转换为单列集合Collection,然后获取Stream流对象 Map<String, String> map = new HashMap<>(); //3.获取Map集合键对应的Set集合对象对应的Stream流对象 Stream<String> s3 = map.keySet().stream(); //4.获取Map集合值对应的Collection集合对象对应的Stream流对象 Stream<String> s4 = map.values().stream(); //5.获取Map集合键值对对应的Set集合对象对应的Stream流对象 Stream<Map.Entry<String, String>> s5 = map.entrySet().stream(); String[] arr = {"张无忌", "张翠山", "张三丰", "张一元"}; //6.获取数组对应的Stream流对象 Stream<String> s6 = Stream.of(arr); //7.获取参数列表对应的Stream流对象 Stream<String> s7 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精"); //8.java.util.Arrays工具类的静态方法stream,也可以把数组转换成Stream流对象 Stream<String> s8 = Arrays.stream(arr); System.out.println(s8); } }
中间操作方法(拼接)
中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程
在Stream流中无法直接修改集合、数组中的数据
public class DemoFilter { public static void main(String[] args) { //创建Stream流对象 Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精"); //1.匿名内部类的方式 /* Stream<String> s2 = s.filter(new Predicate<String>() { @Override public boolean test(String name) { //过滤出所有带娃的 return name.contains("娃"); } }); */ //2.使用lambda表达式的标准格式 /*Stream<String> s2 = s.filter((String name) -> { return name.contains("娃"); });*/ //3.使用lambda表达式的简化格式 Stream<String> s2 = s.filter(name -> name.contains("娃")); //遍历输出 s2.forEach((String name)->{ System.out.println(name); }); } }
public class DemoLimitSkip { public static void main(String[] args) { //创建Stream流对象 Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精"); //步骤一: 只要前7个 Stream<String> s2 = s.limit(7); //步骤二: 跳过前4个 Stream<String> s3 = s2.skip(4); //遍历输出 s3.forEach((String name)->{ System.out.println(name); }); } }
public class DemoDistinct { public static void main(String[] args) { //创建Stream流对象 Stream<String> s1 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃","爷爷", "蛇精", "蝎子精","大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃","爷爷", "蛇精", "蝎子精"); Stream<String> s2 = s1.distinct(); //遍历输出 s2.forEach((String name)->{ System.out.println(name); }); } }
public class DemoConcat { public static void main(String[] args) { //创建Stream流对象 Stream<String> s1 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃"); Stream<String> s2 = Stream.of("爷爷", "蛇精", "蝎子精"); //把s1和s2合并 Stream<String> s12 = Stream.concat(s1, s2); //遍历输出 s12.forEach((String name)->{ System.out.println(name); }); } }
终结操作方法(终结)
终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了
public class DemoForEach { public static void main(String[] args) { Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精"); //1.匿名内部类的方式 /*s.forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } });*/ //2.使用lambda表达式的标准格式 /*s.forEach((String name)->{ System.out.println(name); });*/ //2.使用lambda表达式的简化格式 s.forEach(name-> System.out.println(name)); } }
public class DemoCount { public static void main(String[] args) { //创建Stream流对象 Stream<String> s = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精"); //获取Stream流对象中的元素的个数 long geShu = s.count(); System.out.println("流对象中的元素个数: " + geShu); } }
Collectors工具类提供了具体的收集方式
public class DemoStreamCollect { public static void main(String[] args) { //创建List集合对象,并添加数据 List<Person> list = new ArrayList<>(); Collections.addAll(list, new Person("张三", 18), new Person("李四", 38), new Person("王五", 28)); //获取List集合对象的Stream流对象 Stream<Person> s = list.stream(); //利用map方法,把每个Person对象的年龄增加两岁后,存储到新的Stream流对象中 Stream<Person> s2 = s.map(new Function<Person, Person>() { @Override public Person apply(Person person) { //把当前Person对象的年龄增加两岁 person.setAge(person.getAge() + 2); return person; } }); //利用collect方法把Stream流对象,转换成List集合对象 list = s2.collect(Collectors.toList()); //遍历新的List集合 list.forEach((Person p)->{ System.out.println(p); }); } }
public class DemoStreamMap { public static void main(String[] args) { // {new Person("张三", 18), new Person("李四", 38), new Person("王五", 28)}; //创建List集合对象strList,存储数据类型String List<String> strList = new ArrayList<>(); //添加多个字符串,每个字符串代表一个Person对象的信息 Collections.addAll(strList,"张三:18","李四:38","王五:28"); //需求: 把List集合对象strList中的每个字符串元素,转换成Person对象,存储到Stream流对象中 //获取List对象strList对应的Stream流对象 Stream<String> s1 = strList.stream(); //使用Stream流对象s1调用map方法,把String元素处理成Person元素,存储新的Stream流对象中 Stream<Person> s2 = s1.map(new Function<String, Person>() { @Override public Person apply(String personInfo) { //String personInfo: "张三:18" String[] array = personInfo.split(":"); return new Person(array[0], Integer.parseInt(array[1])); } }); //遍历存储Person对象的Stream流对象 s2.forEach(new Consumer<Person>() { @Override public void accept(Person person) { System.out.println(person); } }); } }
补充知识排序Stream.Sorted public class DemoStreamSorted { public static void main(String[] args) { //创建List集合对象,并添加数据 List<Person> list = new ArrayList<>(); Collections.addAll(list, new Person("张三", 18), new Person("李四", 38), new Person("王五", 28)); //借助Stream流对象,对List集合中的Person对象按照age从小到大排序 //获取List集合对象的Stream流对象 Stream<Person> s = list.stream(); //使用Stream流对象调用sorted方法,指定排序规则 /*Stream<Person> s2 = s.sorted(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return o1.getAge() - o2.getAge(); } });*/ //调用sorted方法,传递的是lambda表达式的简化格式 Stream<Person> s2 = s.sorted((p1, p2) -> p1.getAge() - p2.getAge()); //遍历 s2.forEach(p-> System.out.println(p)); } }
补充Stream流转到数组中 Object[] toArray(); public class Demo1 { public static void main(String[] args) { Stream<String> s = Stream.of("10","20","30","40","50"); Object[] objArray = s.toArray(); System.out.println(Arrays.toString(objArray)); } }
Foreach补充知识点
单例Collection-Foreach遍历
public class DemoCollectionForeach { public static void main(String[] args) { //创建Collection集合 Collection<String> coll = new ArrayList<>(); //添加元素 Collections.addAll(coll, "Hello", "Java", "C++", "Python"); //单列和双列集合内部都有foreach方法,直接调用即可 //单列集合调用forEach方法,传递匿名内部类对象 coll.forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }); //单列集合调用forEach方法,传递lambda表达式标准格式 coll.forEach((String str)->{ System.out.println(str); }); //单列集合调用forEach方法,传递lambda表达式简化格式 coll.forEach(str-> System.out.println(str)); } }
双列Map-Foreach遍历
public class DemoMapForeach { public static void main(String[] args) { //创建Map集合对象,并添加键值对 Map<String, String> map = new HashMap<>(); map.put("项羽", "虞姬"); map.put("吕布", "貂蝉"); map.put("刘备", "孙尚香"); //Map集合有forEach方法 //双列集合调用forEach方法,传递匿名内部类对象 map.forEach(new BiConsumer<String, String>() { @Override public void accept(String s, String s2) { System.out.println(s + "::::" + s2); } }); //双列集合调用forEach方法,传递lambda表达式标准格式 map.forEach((String key, String value) -> { System.out.println(key + "===" + value); }); //双列集合调用forEach方法,传递lambda表达式简化格式 map.forEach((key, value) -> System.out.println(key + "....." + value)); } }