【转】 【JavaSE】黑马程序员 刘意 基础部分笔记(二)

 
 
 
 
 
💜 lambda表达式
格式标准
格式:
  • (形式参数) -> {代码块}
  • 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
  • -> 箭头:由英文中画线和大于符号组成,固定写法。代表指向动作
  • 代码块:方法体内容
组成 Lambda表达式的三要素:
  • 形式参数,箭头,代码块
使用前提:必须要有接口,接口中仅有一个抽象方法
注意事项:
必须要有接口
必须要有上下文环境
 
 
 
例如:创建一个线程
new Thread (()-> { System.out.println("多线程"); }).start();
 
练习1
public interface FlyAble { void fly(String s); }
 
 
public class LambdaDemo { public static void main(String[] args) { //匿名内部类方式 usefaly(new FlyAble() { @Override public void fly(String s) { System.out.println(s); } }); System.out.println("_________"); //lambda表达式形式 usefaly((String s)->{ System.out.println(s); }); } public static void usefaly(FlyAble fly){ fly.fly("万里晴空"); } }
 
可以看出lambda表达式实际是在实例化接口对象,并让其作为参数传递
 
FlyAble f = s{ System.out.println("飞机飞了"); }; usefaly(f);//只输出飞机飞了
 
 
 
 
Lambda表达式的省略模式
省略的规则
  • 参数类型可以省略。但是有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,那么小括号可以省略
  • 如果代码块的语句只有一条,可以省略大括号和分号,和 return关键字可以省略。
 
 
Lambda表达式和匿名内部类的区别
所需类型不同
  • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
  • Lambda 表达式:只能是接口
使用限制不同
  • 如果接口中有且仅有一个抽象方法,可以使用 Lambda表达式,也可以使用匿名内部类
  • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用 Lambda表达式
实现原理不同
  • 匿名内部类:编译之后,产生一个单独的 .class字节码文件
  • Lambda 表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
 
 
方法引用
类名::instMethod
对象方法引用:会使用lambda表达式中的第一个参数去作为对象,引用类的方法
若Lambda参数列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数时,可以使用对象方法引用。
(x, y) -> x.equals(y);
String::equals;
 
 
类型
语法
对应的Lambda表达式
静态方法引用
类名::staticMethod
(args) -> 类名.staticMethod(args)
实例方法引用
inst::instMethod
(args) -> inst.instMethod(args)
对象方法引用
类名::instMethod
(inst,args) -> 类名.instMethod(args)
构造器引用
类名::new
(args) -> new 类名(args)
 
 
💜 接口中的方法组成
 
  • 常量
  • public static final
  • 抽象方法
  • public abstract
  • 默认方法 (Java 8)
  • 静态方法 (Java 8)
  • 私有方法 (Java 9)
 
 
接口中的默认方法
设想,如果一个接口更新了一些抽象方法,那么将会导致所有实现该接口的类都必须强制性的重写该方法,但是在实际生活中,有些类并不需要这些新添加的方法,他们想自由的重写,该怎么办呢?
这就用到了默认方法。
注意事项
  • 默认方法不是抽象方法,所以不强制被重写。
  • 默认方法也可以被重写,重写的时候去掉 default关键字
  • public 可以省略,default不能省略
  • 在接口中default方法是可以有方法体的。
default void show3() { }
 
 
接口中的静态方法
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
static void show() { }
 
 
接口中私有方法
 
私有方法产生原因
Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔:Java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:
当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性。
private void show() { } private static void method() { } // 运行时出错不允许使用private //private:   接口是需要其他类实现的, 如果方法定义成private, 那么其他任何类都不能访问。 这样的方法即要求被实现,又对任何类不可见, 这是无法实现的。
注意
  • 默认方法可以调用私有的静态方法和非静态方法
  • 静态方法只能调用私有的静态方法
 
函数式接口
函数式接口概述
 
概念
  • 有且仅有一个抽象方法的接口
如何检测一个接口是不是函数式接口
加上注解:@FunctionalInterface
放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
 
函数式接口作为方法的参数
函数式接口作为方法的返回值
public static void main(String[] args) { ArrayList<String> array=new ArrayList<String>(); array.add("a"); array.add("bb"); array.add("cccccc"); array.add("ddd"); System.out.println("排序前"+array); Collections.sort(array,getComparator()); System.out.println("排序后"+array); } public static Comparator<String> getComparator(){ //返回一个函数式接口 // return new Comparator<String>() { // @Override // public int compare(String s1, String s2) { // return s1.length()-s2.length(); // } // }; // return (String s1,String s2)->{return s1.length()-s2.length();}; return (s1,s2)->s1.length()-s2.length(); }
 
 
常用的函数式接口
其实都是只有一个抽象方法的接口,都必须搭配lambda表达式使用。
 
🍋 Supplier
Supplier接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。
常用方法:只有一个无参的方法
T get() 按照某种实现逻辑(由Lambda表达式实现)返回一个数据
 
 
Supplier练习1:返回指定类型
public static void main(String[] args) { String s = getString(() -> { return "sss";//实例设置好的的返回 }); System.out.println(s); Integer i=getInteger(()->{return 100;});//实例设置好的的返回 System.out.println(i); } private static String getString(Supplier<String> sup){ return sup.get();//返回传进来的 实例的 get方法的 返回值 } private static Integer getInteger(Supplier<Integer> sup){ return sup.get(); }
 
 
Supplier练习2:返回数组的最大值
{ public static void main(String[] args) { int[] arr={10,332,2223,435}; int maxvalue = getMax(() -> { int max = arr[0]; for (int i = 0; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } return max;//作为传递的实例的返回 }); System.out.println(maxvalue); } private static int getMax(Supplier<Integer> sup){ return sup.get(); //实际上是把实例的return 返回回去 } }
 
 
🍋 Consumer
 
Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
void accept(T t)
对给定的参数执行此操作
default Consumer andThen(Consumer after)
返回一个组合的Consumer,依次执行此操作,然后执行after操作
 
public class ConsumerDemo { public static void main(String[] args) { operatorString("林青霞",s-> System.out.println(s), s-> System.out.println(new StringBuilder(s).reverse().toString())); } private static void operatorString(String name, Consumer<String> con1,Consumer<String> con2){ con1.andThen(con2).accept(name); } }
 
 
练习1:使用两个函数式接口完成打印名字和年龄两个功能
{ public static void main(String[] args) { String[] strArray={"林青霞,30","张曼玉,23","风清扬,33"}; printInfo(strArray,(String str)->{ String name = str.split(",")[0]; System.out.print("姓名:"+name+" "); },(String str)->{ String age= str.split(",")[1]; System.out.println("年龄:"+age); }); // printInfo(strArray,str->System.out.print("姓名:"+str.split(",")[0]+" "), // str->System.out.println("年龄:"+str.split(",")[1])); } private static void printInfo(String[] strArray, Consumer<String> con1,Consumer<String> con2){ for (String str:strArray){ con1.andThen(con2).accept(str); } } }
 
 
 
🍋 Predicate 接口
Predicate接口通常用于判断参数是否满足指定的条件
方法名
说明
boolean test(T t)
对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
default Predicate negate()
返回一个逻辑的否定,对应逻辑非
default Predicate and(Predicate other)
返回一个组合判断,对应短路与
default Predicate or(Predicate other)
返回一个组合判断,对应短路或
{ public static void main(String[] args) { boolean vuale = checkLength("hello", s -> s.length() > 8); System.out.println(vuale); } private static boolean checkLength(String s, Predicate<String> pre1){ //return pre1.test(s); return pre1.negate().test(s); // default Predicate<T> negate() { // return (t) -> !test(t); } }
 
boolean b = checkLength("hello", s -> s.length() > 8, s -> s.length() < 34); System.out.println(b); private static boolean checkLength(String s, Predicate<String> pre1,Predicate<String> pre2){ // boolean b1 = pre1.test(s); // boolean b2 = pre2.test(s); // return b1&&b2; return pre1.and(pre2).test(s); } }
 
PredicateDemo02.java
 
 
🍋 Function
 
Function<t,r>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
R apply(T t)
将此函数应用于给定的参数
default Function andThen(Function after)
返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
 
FunctionDemo.java
 
 
🍋 stream流
生成 Stream流的方式
Collection 体系集合
使用默认方法stream()生成流, default Stream stream()
Map 体系集合
把Map转成Set集合,间接的生成流
数组
通过Stream接口的静态方法of(T... values)生成流
 
list.stream().filter(s-> {return s.startsWith("张");}).forEach(System.out::println); //.sream()是创建流操作 //filter是中间操作 //forEach是终结操作
 
0
 
{ //Collection体系的集合可以使用默认方法stream()生成流 List<String> list =new ArrayList<String>(); Stream<String> listStream = list.stream(); Set<String> set=new HashSet<String>(); Stream<String> hashset = set.stream(); //Map体系的集合间接的生成流 Map<String,Integer> map=new HashMap<>(); Stream<String> keystream = map.keySet().stream(); Stream<Integer> valuestream = map.values().stream(); Stream<Map.Entry<String, Integer>> entrystream = map.entrySet().stream(); //数组可以通过Stream接口的静态方法of(T... values)生成流 String[] strArray={"hello","world","java"}; Stream<String> strArraystream = Stream.of(strArray); Stream<Integer> integerStream = Stream.of(10, 20, 30); }
 
 
Stream流中间操作方法
方法名 说明
Stream filter(Predicate predicate) 用于对流中的数据进行过滤
Stream limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据
Stream skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static Stream concat(Stream a, Streamb)合并a和b两个流为一个流
Stream distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流
Stream sorted() 返回由此流的元素组成的流,根据自然顺序排序
Stream sorted(Comparator comparator)返回由该流的元素组成的流,根据提供的Comparator进行排序
Stream map(Function mapper) 返回由给定函数应用于此流的元素的结果组成的流
IntStream mapToInt(ToIntFunction mapper) 返回一个IntStream其中包含将给定函数应用于此流的元素的结果
 
 
limit()取前几位、skip()跳过前几个
0
 
sorted(),比较器
public class StreamDemo2 { public static void main(String[] args) { ArrayList<String> list=new ArrayList<>(); list.add("linqingxia"); list.add("zhangmanyu"); list.add("wangzuxian"); list.add("liuyan"); list.add("diaochan"); list.add("zhaomin"); //无参事 自然排序:按照字母顺序 // list.stream().sorted().forEach(System.out::println); //有参数 参数是lambda表达式 //一个表达式只会按长度排序 // list.stream().sorted((s1,s2)-> s1.length()-s2.length()).forEach(System.out::println); //参数传递一个lambda表达式实现多个条件判断 //当长度相同时,应该比较字母顺序 list.stream().sorted((s1,s2)->{ int num=s1.length()-s2.length(); int num2=num==0?s1.compareTo(s2):num; return num2; }).forEach(System.out::println); } }
 
map 与 mapToInt
mapToInt会返回一个标准的int流,intStream类型。可以使用sum()函数求和
 
ArrayList<String> strlist=new ArrayList<>(); strlist.add("1"); strlist.add("2"); strlist.add("1"); strlist.add("2"); strlist.add("1"); strlist.add("2"); strlist.stream().map(s->Integer.parseInt(s)).forEach(System.out::println); int sum=strlist.stream().mapToInt(Integer::parseInt).sum(); System.out.println(sum);
 
 
 
Stream流终结操作方法
概念
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。
方法名
说明
void forEach(Consumer action)
对此流的每个元素执行 某种 操作
long count()
返回此流中的元素个数
 
 
练习:男演员女演员筛选
 
注意:Stram流只允许使用一次,所以注释方式分开写会报错:
stream has already been operated upon or closed 流已经被打开或关闭
public class StreamTest { public static void main(String[] args) { //创建集合 ArrayList<String> manList = new ArrayList<String>(); manList.add("周润发"); manList.add("成龙"); manList.add("刘德华"); manList.add("吴京"); manList.add("周星驰"); manList.add("李连杰"); ArrayList<String> womanList = new ArrayList<String>(); womanList.add("林心如"); womanList.add("张曼玉"); womanList.add("林青霞"); womanList.add("柳岩"); womanList.add("林志玲"); womanList.add("王祖贤"); //男演员只要名字为3个字的前三人 // Stream<String> manStream = manList.stream(); // // manStream.filter(s->s.length()==3).limit(3); // // //manList.stream().filter(s->s.length()==3).limit(3); // // //女演员只要姓林的,并且不要第一个 // Stream<String> womanStream = womanList.stream(); // womanStream.filter(s->s.startsWith("林")).skip(1); // // // womanList.stream().filter(s->s.startsWith("林")).skip(1); // //把过滤后的男演员姓名和女演员姓名合并到一起 // Stream<String> constream = Stream.concat(manStream, womanStream); // // // // //把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据 // constream.map(Actor::new).forEach(s-> System.out.println(s.getName())); Stream.concat(manList.stream().filter(s->s.length()==3).limit(3), womanList.stream().filter(s->s.startsWith("林")).skip(1)).map(Actor::new).forEach( s-> System.out.println(s.getName()) ); } }
 
下面这样也可以:
注意中间操作时不要断,不能重复使用stream流
Stream<String> manstream = manList.stream().filter(s->s.length()==3).limit(3); Stream<String> womansream= womanList.stream().filter(s->s.startsWith("林")).skip(1); Stream<String> constream= Stream.concat(manstream,womansream); constream.map(Actor::new).forEach(s-> System.out.println(s.getName()));
 
 
Stream流的收集操作
 
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。
方法名
说明
R collect(Collector collector)
把结果收集到集合中
工具类 Collectors提供了具体的收集方式
方法名
说明
public static Collector toList()
把元素收集到List集合中
public static Collector toSet()
把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper)
把元素收集到Map集合中
 
//创建List集合对象 List<String> list = new ArrayList<String>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); //需求1:得到名字为3个字的流 Stream<String> liststream=list.stream().filter(s->s.length()==3); //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历 List<String> names = liststream.collect(Collectors.toList()); for (String name:names){ System.out.println(name); } //定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成 String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"}; //需求5:得到字符串中年龄数据大于28的流 Stream<String> arraystream=Stream.of(strArray).filter(s->Integer.parseInt(s.split(",")[1])>28); //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值 Map<String,Integer> map= arraystream.collect(Collectors.toMap(s -> s.split(",")[0], s->Integer.parseInt(s.split(",")[1]))); Set<String> keySet = map.keySet(); for (String key:keySet){ Integer value = map.get(key); System.out.println(key+","+value); }
 
 
 
💜 反射
 
反射获取:class类的对象
0
 
反射获取:构造方法
0
 
练习2
/* * 通过反射:访问私有构造器生成对象实例 * */ public class fansheDemo01 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //获取class对象 Class<?> c = Class.forName("fanshe.Student"); // private Student(String name) Constructor<?> con = c.getDeclaredConstructor(String.class); //访问私有方法:暴力反射 con.setAccessible(true); //实例化 Object obj = con.newInstance("林青霞"); System.out.println(obj); }
 
 
反射获取:类的成员变量
 
public class GetFieldDemo { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<?> c = Class.forName("fanshe.Student"); // Field[] fields = c.getFields(); Field[] fields = c.getDeclaredFields(); for (Field field:fields){ System.out.println(field); } System.out.println("---------------"); //通过获取到的字段赋值 //获取单个成员变量 Field addressField = c.getDeclaredField("address"); addressField.setAccessible(true);//注意顺序 //创建对象 Constructor<?> con = c.getDeclaredConstructor(); con.setAccessible(true);//注意顺序 Object obj = con.newInstance(); //通过field的方法给对象的对应成员变量赋值 addressField.set(obj,"西安"); System.out.println(obj); } }
 
 
反射获取:类的成员方法
0
 
0
 
0
 
 
 
练习:通过反射跳过泛型检查
/* * 我有一个 ArrayList<Integer>集合,现在我想在这个集合中添加字符串类型的数据,该怎么实现呢? * */ public class ReflectTset01 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //创建集合、 ArrayList<Integer> array = new ArrayList<Integer>(); array.add(10); array.add(20); array.add(30); //通过反射获取类并访问add成员方法,添加任意类型的参数 Class<? extends ArrayList> c = array.getClass(); Method method = c.getMethod("add", Object.class);//这里add的参数变成了Object method.invoke(array, "hello"); method.invoke(array, "world"); method.invoke(array, "Java"); System.out.println(array);//[10, 20, 30, hello, world, Java]
 
 
练习2:运行配置文件的指定内容
/* *文件配置信息class.txt如下 * * className=Reflect04.Teacher methodName=teach * */ public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //从配置文件加载数据 Properties prop=new Properties(); FileReader fr=new FileReader("class.txt"); prop.load(fr); fr.close(); String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); //通过反射得到类 Class<?> c = Class.forName(className); Constructor<?> con = c.getConstructor(); Object obj = con.newInstance(); Method method = c.getMethod(methodName); method.invoke(obj); } }
 
模块化
 
0
 
0
 
0
 
0
 
0
 
posted @ 2020-10-12 11:03  CLASSIC~W  阅读(185)  评论(0编辑  收藏  举报