*Lambda表达式
新的日期API——Date time
引入Optional——防止空指针异常
*接口的默认方法和静态方法
*新增方法引用格式
*新增Stream类
注解相关的改变
支持并行(Parallel)数组
对并发类(Concurrency)的扩展
JavaFx
例:
@FunctionalInterface public interface MyFunctionalInterface { /** * 有且仅有一个抽象方法 */ void method(); /** * 静态方法 */ static void get(){ } /** * 实现接口方法体 */ default void defaultMethod() { System.out.println("接口默认方法!"); } }函数式思想:只关注做什么,不关注怎么做。
有且仅有一个抽象方法的接口可以适用于Lambda使用的接口(只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导)格式:
public interface 接口名称{ 返回值 方法名称(); }三要素:参数、箭头、代码 即 (参数1,参数2…)->{}
无参时使用括号(),有参数使用逗号分隔箭头是固定写法大括号相当于方法体 解决的问题:有些场景下的代码执行后结果不一定会被使用,造成性能浪费
浪费案例 private void log(int level,String msg) { if(level == 1){ System.out.println(msg); } } @Test public void testStringConcat() { String str1 = "hhh"; String str2 = "csl"; String str3 = "csl123"; log(1,str1+str2+str3); } 存在问题:无论level是否满足条件,log的第二个参数的那三个字符串一定会首先进行拼接并传入方法,然后才开始判断level。
使用Lambda优化案例: private void log2(int level, MessageBuilder builder){ if (level == 1) { System.out.println(builder.builderMessage()); } } /** * 使用Lambda表达式实现字符串的拼接,并验证了延时执行 */ @Test public void testStringConcatLambda() { String str1 = "hhh"; String str2 = "csl"; String str3 = "csl123"; // Lambda方式进行延时执行 // 如果不符合要求,lambda将不会执行;即level=2时不会执行 log2(1, () -> str1+str2+str3); } 如果方法的参数是一个函数式接口类型,那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数,就是使用函数式接口作为方法参数。 例如 java.lang.Runnable接口就是一个函数式接口,假设有一个 startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参。这种情况其实和Thread类的构造方法参数为Runnable没有本质区别。
有参数,且需要返回值。
@FunctionalInterface public interface Function<T, R> { /** *根据类型T的参数获取类型R的结果 */ R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** *先进行操作再进行操作 */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; } } public class FunctionTest { @Test public void testFunction(){ int num = parseInteger( Integer::parseInt, "10" ); System.out.println(num); } private Integer parseInteger(Function<String,Integer> function,String str){ return function.apply(str); } /** * 自定义函数模型拼接 */ @Test public void testAge(){ String str = "csl,16"; int ageNum = getAgeNum( s -> s.split(",")[1], Integer::parseInt, i -> i + 100, str ); System.out.println(ageNum); } /** * * @param one 将字符串截取数字年龄部分,得到字符串 * @param two 将上一步的字符串转换为int类型的数字 * @param three 将上一步的int数字累加100得到的结果 * @param str 处理的字符串 * @return 返回处理结果 */ private int getAgeNum(Function<String,String> one,Function<String,Integer> two,Function<Integer,Integer> three,String str) { return one.andThen(two).andThen(three).apply(str); } } 无参数,指定返回值类型,经常用于只关注过程的代码。
@FunctionalInterface public interface Supplier<T> { /** * 用来获取一个泛型参数指定类型的对象数据,即对外提供 */ T get(); } public class SupplierTest { @Test public void testSupplier() { User user = getUser(User::new); System.out.println(user); } private User getUser(Supplier<User> supplier){ return supplier.get(); } /** * 获取最小值 */ @Test public void testMin() { int[] arr = {12,54,65,43,76,98,9}; int minNum = getMin(() -> { int min = arr[0]; for (int item : arr ) { if (item < min) { min = item; } } return min; }); System.out.println(minNum); } private int getMin(Supplier<Integer> supplier){ return supplier.get(); } } 不需要返回值,有参数,经常用于迭代。
@FunctionalInterface public interface Consumer<T> { /** *消费一个指定泛型的数据 */ void accept(T t); /** *参数和返回值都是Consumer类型;首先做一个操作再做一个操作 */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } } public class ConsumerTest { /** * 单个参数 */ @Test public void testConSummerTest(){ User user = new User(); setUserDefaultSex(u -> u.setSex("男"),user); System.out.println(user); } private void setUserDefaultSex(Consumer<User> conSummer,User user) { conSummer.accept(user); } /** * 一个参数 */ @Test public void testConSummerTest2(){ User user = new User(); setUserDefaultNameAndSex(u -> u.setSex("男"),u->u.setName("张三"),user); System.out.println(user); } private void setUserDefaultNameAndSex(Consumer<User> one,Consumer<User> two,User user) { one.andThen(two).accept(user); } /** * 多个参数 */ @Test public void testConSummerTest3(){ User user = new User(); setUserDefault(u -> u.setSex("男"),u->u.setName("张三"),u->u.setId(1),user); System.out.println(user); } private void setUserDefault(Consumer<User> one,Consumer<User> two,Consumer<User> three,User user) { one.andThen(two).andThen(three).accept(user); } } 返回true/false,经常用于判断。
@FunctionalInterface public interface Predicate<T> { /** *用于条件判断的场景 */ boolean test(T t); /** *与 */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** *取反 */ default Predicate<T> negate() { return (t) -> !test(t); } /** *或 */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } } public class PredicateTest { /** * 一个条件 */ @Test public void testPredicate() { strLongThan( s->s.length()>5,"实例" ); } private void strLongThan(Predicate<String> predicate,String str) { boolean flag = predicate.test(str); System.out.println("判断结果:"+flag); } /** * 两个条件 */ @Test public void testSuccess(){ successThan( s->s.contains("高"),s->s.contains("帅"),"高富" ); } private void successThan(Predicate<String> one,Predicate<String> two,String str) { boolean flag = one.and(two).test(str); System.out.println("强吗:"+flag); } /** * 集合筛选 */ @Test public void testFilter() { String[] array = {"迪丽热巴,女","马儿扎哈,男","地瓜嘎嘎,男","略略略,女"}; List<String> list = filter( s -> s.split(",")[0].length() == 4, s -> "男".equals(s.split(",")[1]), array ); System.out.println(list); } private List<String> filter(Predicate<String> one,Predicate<String> two,String[] arr){ List<String> list = new ArrayList<>(8); for (String s: arr ) { boolean flag = one.and(two).test(s); if (flag){ list.add(s); } } return list; } }方法引用符:::(双冒号)
通过对象名引用成员方法;通过类名称引用静态方法;通过super引用成员方法;通过this引用成员方法。 专注于做什么,而不是怎么做;解决集合中的常见问题。
1.获取流
List<String> list = new ArrayList<>(8); Set<String> set = new HashSet<>(8); Map<String,Object> map= new HashMap<String, Object>(8); String[] array = {"陈西瓜","张收到","呜哈哈","陈开心","王开心","张开心","样开心","李难过"};Collection接口实现类获取流
// Collection接口的实现类获取流 Stream<String> streamList = list.stream(); Stream<String> streamSet = set.stream(); }Map接口实现类获取流
// Map接口的实现类获取流 Stream<String> streamKey = map.keySet().stream(); Stream<Object> streamValue = map.values().stream();数组获取流
// 数组获取流 Stream<String> streamArray = Stream.of(array);2.流的常用方法
List<String> list = new ArrayList<>(8); list.add("陈西瓜"); list.add("张收到"); list.add("呜哈哈"); list.add("陈开心"); list.add("王开心"); list.add("张开心"); list.add("杨开心"); list.add("李难过"); 逐一处理:forEach list.stream().forEach(System.out::print); 过滤:filter list.stream().filter(e->e.contains("开心")); 映射:map(将stream里面的内容映射到另一个stream中) list.stream().map(e -> e.substring(2)); 统计个数:count list.stream().count(); 取用前n个:limit list.stream().limit(n); 跳到前n个:skip list.stream().skip(n); 通过skip+limit实现分页效果:skip+limit list.stream().skip(n).limit(n); 合并两个流:concat Stream.concat(one, two); 将流转换为集合:collect list.stream().collect(Collectors.toList());关于流的常用方法使用案例:
@Test public void testCommonMethod() { List<String> list = new ArrayList<>(8); list.add("陈西瓜"); list.add("张收到"); list.add("呜哈哈"); list.add("陈开心"); list.add("王开心"); list.add("张开心"); list.add("杨开心"); list.add("李难过"); System.out.print("逐一处理:"); list.stream().forEach(System.out::print); System.out.print("\n过滤:"); list.stream().filter(e->e.contains("开心")).forEach(System.out::print); System.out.print("\n映射(将stream里面的内容映射到另一个stream中):"); list.stream().map(e -> e.substring(2)).forEach(System.out::print); System.out.print("\n统计个数. 即list.size(): "); System.out.print(list.stream().count()); System.out.print("\n取用前3个: "); list.stream().limit(3).forEach(System.out::print); System.out.print("\n跳到前1个:"); list.stream().skip(1).forEach(System.out::print); System.out.print("\n通过limit+skip可以实现分页效果:"); list.stream().skip(2).limit(2).forEach(System.out::print); System.out.print("\n合并两个流:"); Stream<String> one = list.stream().skip(0).limit(2); Stream<String> two = list.stream().skip(5).limit(2); Stream.concat(one, two).forEach(System.out::print); System.out.print("\n将流转为集合:"); List<String> collect = list.stream().collect(Collectors.toList()); collect.forEach(System.out::print); }