公司网站平台的作用/网络推广平台软件
JDK8新特性
Lambda表达式
之前存在的问题
使用匿名内部类1.定义了一个没有名字的类2.这个类实现了runnable接口3.创建了这个类的对象
存在的问题语法冗余Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中(即方法中)使用时直接使用lambda表达式
new Thread(new Runnable(){@Overridepublic void run(){System.out.println("线程执行")}
}).start();
new Thread(() -> {System.out.println("线程执行")
}).start();
标准格式
(参数列表) -> {}
省略格式
1.参数类型可以省略
2.小括号内只有一个参数,小括号省略
3.大括号内只有一条语句,省略大括号、return和分号
匿名内部类和Lambda表达式区别
1.所需类型不同匿名内部类:需要的类型可以是类,接口,抽象类Lambda表达式:只能是接口
2.抽象方法的数量不一样匿名内部类所需的接口中抽象方法的数量随意Lambda表达式所需的接口只能有一个抽象方法
3.实现原理不同匿名内部类是在编译后形成class文件Lambda表达式是在程序运行的时候动态生成class
常用内置函数式接口
JDK8接口新增的两个方法
jdk8之前的接口
interface 接口名{静态常量;抽象方法
}
jdk8接口
interface 接口名{静态常量;抽象方法;默认方法; //接口名不能调用,只能继承类对象 调用静态方法; //实现类不能继承
}
常用内置函数式接口
Supplier接口
==java.util.function.Supplier==接口,它意味着供给,对应的Lambda表达式需要"对外提供"一个符合泛型类型的对象
@FunctionalInterFace
public interface Supplier<T> {public abstract T get();
}
供给型接口,通过Supplier接口中的get方法可以得到一个值,无参有返回的接口
使用Lambda表达式返回数组元素最大值
使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值,提示:接口的泛型请使用Integer类
public class DemoSupplier{public static void main(String[] args) {printMax(() -> {int[] arr = {10, 20, 100, 30, 40, 50};//先排序,最后就是最大值Arrays.sort(arr);return arr[arr.length - 1]; //最大值});}private static void printMax(Supplier<Integer> supplier){int maxNum = supplier.get();System.out.prinln(maxNum)}}
Consumer接口
==java.util.function.Consumer==接口,不是生产一个数据,而是消费一个数据,其数据类型由泛型参数决定
@FunctionalInterface
public interface Consumer<T> {public abstract void accept(T t);
}
使用Lambda表达式将一个字符串转成大写和小写的字符串
public class DemoConsumer{public static void main(String[] args) {test(s -> System.out.println(s.toLowerCase()));s -> System.out.println(s.toUpperCase()));}public static void test(Consumer<String> consumer1, Consumer<String> consumer2) {String str = "HelloWorld";//consumer1.accept(str);//consumer2.accept(str)//先执行1在执行2consumer1.andThen(consumer2).accept(str)l;}
}
Function接口
==java.util.function.Function<T,R>==接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件,有参数有返回值
@FunctionalInterface
public interface Function<T,R> {public abstract R apply(T t);
}
使用Lambda表达式将字符串转成数字
public class DemoFunction {public static void main(String[] args) {test(s -> Interger.parseInt(s));}public static void test(Function<String,Integer> function) {Integer in = function.apply("10");System.out.println(in);}
}
andThen方法两次操作,同上
Predicate接口
==java.util.function.Predicate==接口返回boolean类型结果,可以对某种类型的数据进行判断
@FunctionalInterface
public interface Predicate<T> {public abstract boolean test(T t);
}
使用Lambda判断一个人名如果超过3个字就认为是很长的名字
public class DemoPredicate {public static void main(String[] args) {test(s -> s.length() > 3, "迪丽热巴");}private static void test(Predicate<String> predicate, String str) {boolean veryLong = predicate.test(str);System.out.println(veryLong);}
}
and(Predicate<T> predicate)函数 与函数t1.and(t2).test(str)or() 或函数negate() 非函数 结果取反
方法引用
Lambda的冗余场景
使用Lambda表达式求一个数组的和
public class DemoMethodRefIntro{//求和public static void getMax(int[] arr) {int sum = 0;for(int n : arr){sum += n;}System.out.println(sum);}public static void main(String[] args) {/*printMax((int[] arr) -> {int sum = 0;for(int n : arr){sum += n;}System.out.println(sum);});*///方法引用//让指定方法重写接口的抽象方法printMax(DemoMethodRefIntro::getMax);}private static void printMax(Consumer<T> consumer) {int[] arr = {10, 20, 30, 40, 50};consumer.accept(arr);}
}
方法引用的格式
符号表示 ::
应用场景:替代Lambda方法
常见引用方式:
1.instanceName::methodName 对象::方法名
2.ClassName::staticMethodName 类名::静态方法名
3.ClassName::methodName 类名::方法名
4.ClassName::new 类名::new调用构造器
5.TypeName[]::new String[]:new调用数组的构造器
对象名::方法名
@Test
public void test(){Date now = new Date();Supplier<Long> su1 = () -> {return now.getTime();};Long aLong = su1.get();System.out.println(aLong);}//方法引用
/*
1.被引用的方法,参数要和接口中抽象方法的参数一样
2.当接口的抽象方法有返回值时,被引用的方法也必须有返回值
*/
@Test
public void test(){Date now = new Date();Supplier<Long> su1 = now::getTime;Long aLong = su1.get();System.out.println(aLong);}
类名::静态方法
@Test
public void test(){Supplier<Long> Su = System::currentTimeMillis;
}
类名::实例方法
@Test
public void test(){//类名::实例方法 实际上会将第一个参数作为方法的调用者Function<String,Integer> f1 = String::length;int length = f1.apply("hello");System.out.println("length = " + length);/*BiFunction<T,U,R>R apply(T, U);*/BiFunction<String, Integer, String> f2 = String::substring;String str2 = f2.apply("helloworld", 3);System.out.println(str2);}
类名::new (自动调用构造器)
@Test
public void test(){Supplier<Person> su1 = Person::new;Person person = su1.get();System.out.println("Person =" + person);
}//有参
@Test
public void test(){BiFunction<String, Integer, Person> bif = Person::new;Person person = bif.apply("zhangsan", 18);System.out.println(person);
}
数组::new (自动调用数组构造器)
@Test
public void test(){Function<Integer, int[]> f1 = int[]::new;int arr[] = f1.apply(10);System.out.println(Arrays.toString(arr));
}
集合之Stream流式操作
集合处理数据的弊端
@Test
public void test(){//ArrayList集合中存储数据//需求//1.拿到所有姓张的//2.再拿到张姓里面名字长度3个字的//3.打印ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");//1.拿到所有姓张的ArrayList<String> zhangList = new ArrayList();for(String name : list){if(name.startsWith("张")){zhangList.add(name);}}//2.拿到名字长度为3个字的ArrayList<String> threeList = new ArrayList();for(String name : zhangList){if(name.length == 3){threeList.add(name);}}//3.打印for(String name : threeList){System.out.println(name);}}
Stream流式思想概述
注意:Stream和IO流没有任何关系
Stream流式思想类似于工厂车间的生产流水线,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序,在流水线上,通过多个工序让一个原材料加工成一个商品
@Test
public void test(){//ArrayList集合中存储数据//需求//1.拿到所有姓张的//2.再拿到张姓里面名字长度3个字的//3.打印ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");//1.拿到所有姓张的;2.拿到姓张的名字三个字的;3.打印list.stream().filter((s) -> {return s.startsWith("张");}).filter((s) -> {return s.length() == 3;}).forEach((s) -> {System.out.println(s);})}
获取Stream流的两种方式
根据Collection获取流
//根据Collection获取流
//Collection接口中有一个默认的方法,default Stream<E> stream()
List<String> list = new ArrayList();
Stream<String> stream1 = list.stream();Set<String> set - new HashSet();
Stream<String> stream2 = set.stream();Map<String, String> map = new HashMap();
Stream<String> stream3 = map.keySet().stream();
Stream<String> stream4 = map.values().stream();
Stream<Map.Entry<String, String>> stream5 = map.entrySet().stream();
Stream中的静态方法of获取流
由于数组对象不可能添加默认方法,所以Stream接口中提供了静态方法of
Stream<String> stream = Stream.of("aa","bb","cc");String[] strs = {"aa","bb","cc"};
Stream<String> stream2 = Stream.of(strs);//基本数据类型的数组不能使用Stream流,会将整个数组看作一个元素
Stream常用方法和注意事项
方法名 | 方法作用 | 返回值类型 | 方法种类 |
---|---|---|---|
count | 统计个数 | long | 终结 |
forEach | 逐一处理 | void | 终结 |
filter | 过滤 | Stream | 函数拼接 |
limit | 取用前几个 | Stream | 函数拼接 |
skip | 跳过前几个 | Stream | 函数拼接 |
map | 映射 | Stream | 函数拼接 |
concat | 组合 | Stream | 函数拼接 |
**终结方法:**返回值类型不再是Stream类型的方法,不再支持链式调用
**非终结方法:**返回值仍然是Stream类型的方法,支持链式调用
注意事项(重要)
1.Stream流调用终结方法后,就会被关闭
2.Stream非终结方法返回新的流
3.Stream不调用终结方法,中间的操作不会执行
常用方法
forEach
List<String> list = new ArrayList();
Collection.addAll(list,"","");
list.stream().forEach(s -> System.out.println(s));
count
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");long count = list.stream().count();
System.out.println(count);
filter
//过滤数据
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");list.stream().filter(s -> s=="a").forEach(System.out::println);
limit
//对流数据进行截取
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");list.stream().limit(2).forEach(System.out::println);
skip
//跳过指定个数数据
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");list.stream().skip(1).forEach(System.out::println);
map
//把一种类型的流转换为另一种类型的流
List<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3");list.stream().map(s -> Integer.parseInt(s)).forEach(s -> System.out.println(s.getClass()));
sorted
//将数据排序,可以默认自然排序(无参),也可以指定比较器(有参)
Stream<Integer> stream = Stream.of(55, 22, 66, 33, 11);
stream.sorted().sorted((o1, o2) -> o2 - o1).forEach(System.out::println);
distinct
//去重 自定义对象去重需要重写equals和hashcode方法
Stream<String> stream = Stream.of("a", "a", "b", "b", "c");
stream.distinct().forEach(System.out::println);
match
Stream接口中提供了三个相关方法boolean allMatch(Predicate<? super T> predicate);//元素是否全部满足条件
boolean anyMatch(Predicate<? super T> predicate);//元素是否有任一个满足条件
boolean noneMatch(Predicate<? super T> predicate);//元素是否全部不满足条件
//allMatch
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
boolean b = stream.allMatch(s -> s < 7);
System.out.println(b);//anyMatch
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
boolean b = stream.anyMatch(s -> s < 3);
System.out.println(b);//noneMatch
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
boolean b = stream.noneMatch(s -> s < 3);
System.out.println(b);
find
//从集合中找到第一个数据
//findFirst
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
Optional<Integer> first = stream.findFirst();
System.out.println(first.get());//findAny
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
Optional<Integer> first = stream.findAny();
System.out.println(first.get());
max和min
//得到最大或最小的值
//max 取最后一个值,自己比较排序好
Optional<Integer> max = Stream.of(5, 4, 3, 2, 1).max((o1, o2) -> o1 - o2);
System.out.println(max.get());//min 取第一个值,自己排序好
Optional<Integer> max = Stream.of(5, 4, 3, 2, 1).min((o1, o2) -> o2 - o1);
System.out.println(max.get());
reduce ***
//将所有数据归纳得到一个数据
Stream<Integer> integerStream = Stream.of(4, 5, 9, 7);//T reduce(T identity, BinaryOperator<T> accumulator);
// T identity是默认值
// BinaryOperator对数据处理的方式
Integer sum = integerStream.reduce(0, (a, b) -> {System.out.println("a = " + a + ";b = " + b);return a+b;
});
System.out.println(sum);
//map和reduce组合使用
//求所有年龄的总和
//1.得到所有年龄
//2.求和
Person p1 = new Person("张三", 20);
Person p2 = new Person("李四", 32);
Person p3 = new Person("王五", 18);
Person p4 = new Person("赵六", 45);Stream<Person> stream = Stream.of(p1, p2, p3, p4);
int ageCount = stream.map(s -> s.getAge()).reduce(0, (a, b) -> a + b);
System.out.println(ageCount);
mapToInt
//Stream流中的Integer数据转换为int数据