Labda表达式
Lambda表达式演示
- Lanbda表达式:是JDK1.8提出的一种新语法。是对之前的某种情况的代码的“简化写法”。
- Lambda表达式演示:
public class Demo01 {
public static void main(String[] args) {
//1.之前我们实现一个线程——可以使用"匿名内部类"的形式:new Thread(Runnable的匿名内部类).start()
/*new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println("敌人开枪:" + i);
}
}
}).start();*/
//2.这种情况就可以使用Lambda
new Thread(()-> {
for (int i = 0; i < 30; i++) {
System.out.println("敌人开枪:" + i);
}
}).start();
for (int i = 0; i < 30; i++) {
System.out.println("我开枪:" + i);
}
}
}
Lambda的使用前提及函数式接口的概念
- Lambda的使用前提:
- 当我们面向的是一个接口时,例如:new Thread(Runnale接口).start()
- 接口中有且仅有一个需要子类必须实现的抽象方法。例如:Runnable接口中的run()方法。
- 函数式接口的概念:
接口中有且仅有一个需要子类必须实现的抽象方法,这种接口就叫:函数式接口
只有使用函数式接口的地方,才可以使用Lambda表达式 - @FunctionaInterface注解:
//我们可以自己定义函数式接口
@FunctionalInterface//此注解可以保证下面定义的接口一定是一个标准的"函数式接口"
interface IAnimal{
public abstract void show();
public default void show1(){
}
public static void show2(){
}
public abstract String toString();//OK,可以定义和Object签名相同的抽象方法,这种方法子类会从Object继承,所以不用必须重写
public abstract boolean equals(Object obj);//OK的。
// public abstract String aString();//错误
}
class Cat implements IAnimal{
@Override
public void show() {
System.out.println("小猫喵喵...");
}
}
public class Demo02 {
public static void main(String[] args) {
//1.调用fun()——传入"子类对象"
fun(new Cat());
//2.调用fun()——传入"匿名内部类对象"
fun(new IAnimal() {
@Override
public void show() {
System.out.println("小狗汪汪...");
}
});
//3.调用fun()——传入"Lambda表达式"
fun(()->{
System.out.println("小猪哼哼...");
});
}
public static void fun(IAnimal a){
a.show();
}
}
函数式编程思想
- 面向对象的编程思想:必须要定义类、创建对象、传入对象
- 函数式编程思想:不用定义类、不用创建对象,只传入“方法(函数)”。
- 好处:
- 简化了写法;
- 提高了效率(不用创建对象)
@FunctionalInterface//此注解可以保证下面定义的接口一定是一个标准的"函数式接口"
interface IAnimal{
public abstract void show();
}
public class Demo02 {
public static void main(String[] args) {
//3.调用fun()——传入"Lambda表达式"
fun(()->{//Lambda表达式:其实就是一个“方法(函数)”——这被称为:函数式编程思想,打破了之前面向对象的编程方式
System.out.println("小猪哼哼...");
});
}
public static void fun(IAnimal a){//IAnimal就是一个“函数式接口”类型
a.show();
}
}
Lambda的标准格式:
- Lambda的标准格式:
- 一对小括号:(就是形参)
- 一个右箭头:->
- 一对大括号:{方法体}
- 抽象方法是无参无返回值的情况:指函数式接口中的抽象方法是“无参,无返回值”的,那么Lambda就是无参无返回值的。
new Thread(()->{
for(int i = 0;i < 30 ; i++){
System.out.println(“敌人开枪:” + i);
}
).start();
- 抽象方法是有参有返回值的情况:指函数式接口中的抽象方法是有参有返回值的,那么Lambda就是有参有返回值的。
public class Demo03 {
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
intList.add(10);
intList.add(59);
intList.add(22);
intList.add(55);
intList.add(88);
intList.add(17);
//对集合元素进行"降序"排序,怎么排??????
/*Collections.sort(intList, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});*/
//我们发现:Comparator就是一个"函数式接口",就意味着可以使用:Lambda表达式
Collections.sort(intList,(Integer o1 ,Integer o2)->{ return o2 - o1;});
System.out.println(intList);
}
}
Lambda的省略格式
- Lambda的省略格式:
-
形参有关:形参的数据类型都可以省略。无论有几个参数。
-
形参有关:如果形参只有一个,可以同时省略:数据类型,一对小括号
如果省略小括号,必须省略数据类型
如果省略数据类型,可以不省略小括号 -
方法体有关:如果方法体只有一句话,可以同时省略:一对大括号,语句后的分号,return关键字(如果有)。三个部分:要省则全部省略,要用则全部使用。
-
代码演示:
//1.自定义一个函数式接口
@FunctionalInterface
interface IAnimal{
public String eat(String s);
}
class Cat implements IAnimal{
@Override
public String eat(String s) {
System.out.println("小猫吃:" + s);
return "小猫";
}
}
public class Demo04 {
public static void main(String[] args) {
//1.传入子类对象
fun(new Cat(),"猫粮");
//2.传入匿名子类对象
fun(new IAnimal() {
@Override
public String eat(String s) {
System.out.println("小狗吃:" + s);
return "小狗";
}
},"骨头");
//3.传入Lambda表达式--完整格式
fun((String s)->{
System.out.println("小猪吃:" + s);
return "小猪";
},"白菜");
//4.传入Lambda表达式--省略格式
//假如:Lambda的方法体中,只有一句:return "小鸡";
fun(x -> "小鸡" , "小米");
//练习:
List<Integer> intList = new ArrayList<>();
intList.add(10);
intList.add(59);
intList.add(22);
intList.add(55);
intList.add(88);
intList.add(17);
Collections.sort(intList, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
//使用省略格式
Collections.sort(intList,(i1,i2)-> i2 - i1);
}
public static void fun(IAnimal a,String s){
String eat = a.eat(s);
System.out.println(eat);
}
}
Lambda的几种使用形式:
- 方法的实参使用Lambda:
new Thread(()->{
for(int i = 0;i < 30 ; i++){
System.out.println(“敌人开枪:” + i);
}
}).start();
- 使用变量的方法:函数式接口 变量名 = Lambda表达式;
Runnable r = ()->{
for(int i = 0;i < 30 ; i++){
System.out.println(“敌人开枪:” + i);
}
};
new Thread(r).start();
- 方法的返回值使用Lambda:
public static void main(String[] args){
Runnable r = getRun();//Runnable r = Lambda表达式;
new Thread(r).start();
}
public static Runnable(函数式接口类型) getRun(){
return ()->{
for(int i = 0;i < 30 ; i++){
System.out.println(“敌人开枪:” + i);
}
};
}
Stream流
- JDK8提出了”Lambda表达式“,同时也提供了一个”Lambda表达式“的应用–Stream流。Stream流类似于”迭代器“,但它比迭代器更强大,它可以结合Lambda对大量的数据进行反复的:筛选,过滤,汇总等操作,用起来比较方便。
public class Demo05 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
//需求:请筛选中集合中所有的"张姓"学员,而且筛选后,只打印"前两名"
List<String> zhangList = new ArrayList<>();
//遍历原集合
for (String s : list) {
if (s.startsWith("张")) {
zhangList.add(s);
}
}
//只打印前两名
for (int i = 0; i < 2; i++) {
System.out.println(zhangList.get(i));
}
System.out.println("----------------------------------------------------");
//使用Stream流 + Lambda表达式
list.stream().filter(s -> s.startsWith("张"))//筛选张姓学员
.limit(2)//保留前两个
.forEach(s -> System.out.println(s));//打印每一个
}
}
Stream流:获取流的方式
- 通过Collection集合获取流:Collection接口中的”默认方法:Stream()“可以获取流:
List<String> list = new ArrayList<>();
...
Stream<String> stream = list.stream();
------------------------------------------------------------------
Set<String> set = new HashSet<>();
...
Stream<String> setStream = set.stream();
- 通过Map集合获取流:Map不能直接获取流,只能获取“键,键值对”的Set集合,然后再获取Set集合的Stream流。
Map<Integer,String> map = new HashMap<>();
map.put(....);
//1.获取键的流
Stream<Integer> keyStream = map.keySet().stream();
//2.获取键值对的流
Stream<Map.Entry<Integer,String>> entryStream = map.entrySet().stream();
//3.获取值的流
Stream<String> valueStream = map.values().stream();
- 通过引用类型数组获取流:
Integer[] arr = {10,20,30,40,50};
Stream<Integer> intStream = Stream.<Integer>of(arr);//只能获取“引用类型数组”的流。
- 通过基本类型数组获取流:
int[] arr = {1,2,3,4,5};
IntStream intStream = IntStream.of(arr);
- 通过一些零散的数据获取流:
Stream<String> strStream = Stream.<String>of(”张三”, ”李四”, ”张三丰”, ”章子怡”);
流式思想及惰性求值
- 在流的方法中,有些方法调用后,程序没有任何打印,这是因为Stream流中采用了:流式操作,惰性求值。
- 流式操作:就类似于流水线,一个节点,一个节点的。下一个节点的工作内容是由上一个节点提供的。
- 惰性求值:
- 拼接方法:此方法会返回一个Stream流,例如:filter
- 终结方法:此方法不是返回一个Stream流,例如:forEach
- Stream流的工作方式:当我们调用Stream流的“拼接方法”时,方法内部指挥记录,不工作。而我们调用Stream流的“终结方法”时,这时才让之前所有节点开始工作—这种工作方式叫:惰性求值。
- 一个Stream流,只能用一次。
代码演示:
public class Demo08 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
/*Stream<String> stream1 = list.stream();
//筛选张姓
Stream<String> stream2 = stream1.filter(s -> s.startsWith("张"));
//筛选三个字的
Stream<String> stream3 = stream2.filter(s -> s.length() == 3);
//打印最终结果
stream3.forEach(s -> System.out.println(s));*/
//写成一句话
list.stream().filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
}
}
Stream流的常用方法:
forEach()逐一处理
forEach()方法的作用:“终结方法”。它内部会循环遍历每个元素,并且调用我们的Lambda表达式,并且将每个元素作为参数传给Lambda表达式。
代码演示:
public class Demo06 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
//1.获取流
Stream<String> stream = list.stream();
//2.操作流:forEach()
/*stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//3.使用Lambda-完整格式
/*stream.forEach((String s)->{
System.out.println(s);
});*/
//4.使用Lambda-省略格式
stream.forEach(s -> System.out.println(s));
System.out.println("=================================================");
//练习
//要求:将上述集合中的所有元素存储到一个新集合中
List<String> newList = new ArrayList<>();
list.stream().forEach(s -> newList.add(s));
System.out.println(newList);
}
}
filter()方法:过滤
filter方法的作用:“拼接方法”。它内部也会遍历每个元素,在遍历时会将每个元素传入到我们的Lambda表达式中,根据表达式的返回结果。
true:会将此元素包含在新流中(可以这样认为)。
false:就会略过此元素。
代码演示:
public class Demo07 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
//筛选出所有的张姓学员
/*Stream<String> stream1 = list.stream();
Stream<String> stream2 = stream1.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张");
}
});
stream2.forEach(s -> System.out.println(s));*/
//改成Lambda--省略格式
list.stream().filter(s -> s.startsWith("张"))
.forEach(s -> System.out.println(s));
}
}
count()方法:统计个数
count方法的作用:”终结方法“,统计筛选的元素数量。
代码演示:
public class Demo09 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
//统计张姓学员的数量
long count = list.stream().filter(s -> s.startsWith("张"))
.count();
System.out.println("张姓学员共有:" + count);
}
}
limit()方法:取前几个元素
limit()方法的作用:”拼接方法“,取筛选的前几个元素。
代码演示:
public class Demo10 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
//筛选出所有的"张姓"学员,取前2名
list.stream().filter(s -> s.startsWith("张"))
.limit(2)
.forEach(s -> System.out.println(s));
}
}
skip()方法:跳过前几个元素
slip()方法的作用:”拼接方法“跳过前几个元素。
代码演示:
public class Demo11 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
//筛选所有张姓学员,跳过前2个
list.stream().filter(s -> s.startsWith("张"))
.skip(2)
.forEach(s -> System.out.println(s));
}
}
map()方法:转型
- map()方法的作用:”拼接方法“可以将一种泛型的流转换为另外一种泛型的流。
代码演示:将Stream 转换为Stream流。
public class Demo12 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("10");
list.add("20");
list.add("30");
list.add("40");
list.add("50");
list.add("60");
list.add("70");
//将list中每个元素 + 5 ,然后打印
/*list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s);
}
}).forEach(n -> System.out.println(n + 5));*/
//使用Lambda
list.stream().map(s -> Integer.valueOf(s))
.forEach(n -> System.out.println(n + 5));
System.out.println("==================================================");
List<String> strList = new ArrayList<>();
strList.add("黄渤");
strList.add("黄晓明");
strList.add("黄磊");
strList.add("黄老邪");
//需求:将集合中每个人名构造一个Student对象,并打印这个对象
/*strList.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
return new Student(s);
}
}).forEach(student -> System.out.println(student));*/
//改成Lambda
strList.stream().map(s -> new Student(s))
.forEach(student -> System.out.println(student));
}
}
concat()方法:组合
Stream流的静态方法:concat()作用:将两个流合并为一个流。
代码演示
public class Demo13 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("黄磊");
list1.add("黄渤");
list1.add("黄老邪");
List<String> list2 = new ArrayList<>();
list2.add("黄奕");
list2.add("杨幂");
list2.add("迪丽热巴");
//将两个集合中的所有元素全部打印
Stream.concat(list1.stream(),list2.stream())
.forEach(s -> System.out.println(s));
}
}
综合案例:
/*
1. 第一个队伍只要名字为3个字的成员姓名;filter()
2. 第一个队伍筛选之后只要前3个人;limit()
3. 第二个队伍只要姓张的成员姓名;filter()
4. 第二个队伍筛选之后不要前2个人;slip()
5. 将两个队伍合并为一个队伍;concat()
6. 根据姓名创建 Person 对象;map()
7. 打印整个队伍的Person对象信息。forEach()
*/
public class Demo14 {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
/*
1. 第一个队伍只要名字为3个字的成员姓名;filter()
2. 第一个队伍筛选之后只要前3个人;limit()
3. 第二个队伍只要姓张的成员姓名;filter()
4. 第二个队伍筛选之后不要前2个人;slip()
5. 将两个队伍合并为一个队伍;concat()
6. 根据姓名创建 Person 对象;map()
7. 打印整个队伍的Person对象信息。forEach()
*/
Stream.concat(one.stream().filter(s -> s.length() == 3).limit(3),
two.stream().filter(s -> s.startsWith("张"))
.skip(2))
.map(s -> new Person(s))
.forEach(person -> System.out.println(person));
}
}
函数拼接与终结方法
Stream流的结果收集到集合和数组中
我们之前的操作结果都是通过forEach()方法打印了。如果我们想将筛选的结果存储到一个新集合,可以通过Stream的一些方法,将筛选的结果转换为集合,数组。
public class Demo15 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("张无忌");
list.add("张三丰");
list.add("刘德华");
list.add("成龙");
list.add("张三");
list.add("李四");
//筛选出所有的张姓学员,存储到一个新集合
List<String> zhangList = list.stream().filter(s -> s.startsWith("张"))
.collect(Collectors.toList());
System.out.println(zhangList);
System.out.println("======================================");
Set<String> zhagnSet = list.stream().filter(s -> s.startsWith("张"))
.collect(Collectors.toSet());
System.out.println(zhagnSet);
System.out.println("======================================");
//提取出数组
Object[] objs = list.stream().filter(s -> s.startsWith("张"))
.toArray();
System.out.println(Arrays.toString(objs));
}
}
Lambda方法的引用
方法引用概述:
- “方法引用”指在我们编写Lambda时,如果已有的某个类中的某个方法已经做了一样的事情,这时就可以省略Lambda表达式,直接引用现有的方法即可
- 方法引用的形式:
1. 通过“对象名”引用“普通成员方法”;
2. 通过“类名”引用“静态成员方法”;
3. 引用某个类的某个“构造方法”;
4. 通过“类名”引用“普通成员方法”【比较特殊,有一定的前提条件】
普通成员方法引用
- 普通成员方法引用:指通过“对象名”引用“它的某个普通成员方法”
- 格式为:
对象名::普通成员方法(注意没有小括号)
使用“方法引用”的前提:必须要能够使用Lambda
代码演示:
测试类
package com.itheima.demo03_Lambda方法引用_普通成员方法引用;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class Demo03 {
public static void main(String[] args) {
//1.制作一个线程,里面模拟敌人开30枪
//使用匿名内部类
/*new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30 ; i++) {
System.out.println("敌人开枪 " + i);
}
}
}).start();*/
//使用Lambda
/*new Thread(()->{
for (int i = 0; i < 30; i++) {
System.out.println("敌人开枪:" + i);
}
}).start();*/
//这时,我们发现Student类中的show()方法的功能跟我们Lambda的功能是一样的,而且show()方法形参、返回值也和Lambda一样的,这时,我们就可以引用Student类的show(),不用写Lambda表达式了。
//引用show是普通成员方法,必须先创建对象
Student stu = new Student();
new Thread(stu::show).start();
//主线程继续向下
for (int i = 0; i < 30; i++) {
System.out.println("我开枪:" + i);
}
System.out.println("====================================");
//练习:
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三丰");
list.add("章子怡");
list.add("张学友");
//使用Stream流打印每个元素
//匿名内部类
/*list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//使用Lambda
// list.stream().forEach(s -> System.out.println(s));
//Lambda整体的功能:接收一个字符串,打印一个字符串
//大家想一想:有没有哪个类的哪个方法也是一样的功能:接收一个字符串,打印一个字符串???????????
//System.out(PrintStream类)里面的一个println(String s):接收一个字符串,向控制台打印一个字符串
//所以:我们Lambda这里就可以引用println(String s)方法
/*PrintStream ps = System.out;
list.stream().forEach(ps::println);*/
//简写
list.stream().forEach(System.out::println);
}
}
Student类
package com.itheima.demo03_Lambda方法引用_普通成员方法引用;
public class Student {
public void show(){
for (int i = 0; i < 30; i++) {
System.out.println("student敌人开枪:" + i);
}
}
public void show1(){
}
}
代码图解:
静态成员方法引用
- 指:通过“类名”引用它的某个“静态成员方法”;
- 格式:
类名::静态方法名(没有小括号)
代码演示:
package com.itheima.demo04_Lambda方法引用_静态成员方法引用;
//1.自定义一个函数式接口
interface ICalc{
public int getMax(int a, int b);
}
public class Demo04 {
public static void main(String[] args) {
//1.匿名内部类
/*fun(new ICalc() {
@Override
public int getMax(int a, int b) {
return a > b ? a : b;
}
},10,20);*/
//2.使用Lambda
// fun((a, b) -> a > b ? a : b, 100, 200);
//3.Lambda整体功能:接收两个int值,并求出一个最大的,然后返回
//想一想:有没有哪个类的,哪个方法跟Lambda的功能是一样的?????????
//Math类中有一个max(int a,int b)就是做一样的事情,而且参数、返回值都一样
//所以:可以省略Lambda,引用Math类的静态方法:max(int a,int b)
fun(Math::max, 1000, 2000);
}
//2.定义一个方法,形参是这个函数式接口类型
public static void fun(ICalc calc, int x, int y) {//fun(ICalc)相当于:Thread(Runnable r)构造方法,都是方法,而且都接收一个:函数式接口,为了后面使用Lambda和方法引用
int max = calc.getMax(x, y);
System.out.println("max = " + max);
}
}
代码图解
构造器引用
代码演示:
测试类
package com.itheima.demo05_Lambda方法引用_构造器引用;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class Demo05 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("章子怡");
list.add("杨幂");
list.add("迪丽热巴");
list.add("古力娜扎");
//使用stream流将这些人名封装成Person对象,并打印这些对象
//使用匿名内部类
/* list.stream().map(new Function<String, Person>() {
@Override
public Person apply(String s) {
return new Person(s);
}
}).forEach(person -> System.out.println(person));*/
//使用Lambda
/*list.stream().map(s -> new Person(s))
.forEach(System.out::println);*/
//Person类的带参的构造方法,也是接收一个String,而且也可以创建一个Person对象
//所以:map()中就可以引用:Person(String s)构造方法
list.stream().map(Person::new)
.forEach(System.out::println);
}
}
Person类
package com.itheima.demo05_Lambda方法引用_构造器引用;
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
代码图解
类的成员方法引用
指通过“类名”引用“普通成员方法”【有一定的使用前提】
代码演示:
package com.itheima.demo06_Lambda方法引用_类的成员方法引用;
//1.定义一个函数式接口
interface IA{
//在第一参数中查找第二个参数的出现位置
public int findStr(String src,String subStr);
}
public class Demo06 {
public static void main(String[] args) {
//1.使用匿名内部类的形式
fun(new IA() {
@Override
public int findStr(String src, String subStr) {
return src.indexOf(subStr);
}
}, "我爱Java", "Java");
//2.使用Lambda
//fun((a, b) -> a.indexOf(b), "我爱Java", "Java");
//3.Lambda的方法体中:调用了第一个参数(String类型)的indexOf(第二个参数(String类型))这种新式
//这时就可以直接引用:第一个参数(String类型)的indexOf()方法
//通过"类名"引用"普通成员方法"
//fun(String::indexOf, "我爱Java", "Java");
}
//2.写一个方法,形参是函数式接口:IA
public static void fun(IA a,String src,String subStr){
int index = a.findStr(src, subStr);//自动调用:int index = src.indexOf(subStr)
System.out.println(subStr + " 在 " + src + " 中出现的位置:" + index);
}
}
代码图解
Base64
Base64概述
- Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法
- 在Java 8 中,Base64编码已经成为Java类库的标准,Java6内置了Base64编码的编码器和解码器。
- Base64工具类提供了一套静态方法获取下面三种Base64编解码器
- 基础:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/.
- URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
- MIME:输出映射到MIME友好格式。输出每行不超过76字符,并且使用‘\r’并跟随“\n”作为分割。编码输出最后没有行分割
- Base64了欸的很多方法都是从java.lang.Object类继承
常用方法:
- public String encodeToString(byte[] src)//使用Base64编码方案将指定的字节数组编码为字符串。
- public byte[] decode(String src)//使用Base64编码方案将Base64编码的字符串解码为新分配的字节数组。
- public static Base64.Encoder getEncoder()//返回一个Base64.Encoder ,它使用Basic类型base64编码方案进行编码。
- public static Base64.Decoder getDecoder()//返回Base64.Decoder解码使用Basic型base64编码方案。
代码演示:
package com.itheima.demo07_Base64加密解密演示;
import java.util.Base64;
import static java.lang.Integer.decode;
public class Demo07 {
public static void main(String[] args) {
String str = "这是一个明文字符串";
String url = "http://localhost:8080/itcast/index?username=张三&pwd=1111";
//编码(加密)
Base64.Encoder ec = Base64.getEncoder();
String s1 = ec.encodeToString(str.getBytes());//6L+Z5piv5LiA5Liq5piO5paH5a2X56ym5Liy
String s2 = ec.encodeToString(url.getBytes());//aHR0cDovL2xvY2FsaG9zdDo4MDgwL2l0Y2FzdC9pbmRleD91c2VybmFtZT3lvKDkuIkmcHdkPTExMTE=
System.out.println("加密:");
System.out.println(s1);//6L+Z5piv5LiA5Liq5piO5paH5a2X56ym5Liy
System.out.println(s2);//aHR0cDovL2xvY2FsaG9zdDo4MDgwL2l0Y2FzdC9pbmRleD91c2VybmFtZT3lvKDkuIkmcHdkPTExMTE=
System.out.println("传输......");
System.out.println("对方接收:");
//解码(解密)
Base64.Decoder dc = Base64.getDecoder();
byte[] bs1 = dc.decode(s1);
byte[] bs2 = dc.decode(s2);
String str1 = new String(bs1);//这是一个明文字符串
String str2 = new String(bs2);//http://localhost:8080/itcast/index?username=张三&pwd=1111
System.out.println("解密:");
System.out.println(str1);
System.out.println(str2);
}
}
代码图解:
.