上一篇 <<<十大经典排序算法汇总-动画演示
下一篇 >>>Java集合类图总览
1.Lambda表达式
Lambda 左边(参数)->右边(主体内容)
优点:代码简单、可能代表未来的编程趋势。
缺点:不容易调试,若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。
new Thread(()->{System.out.println(Thread.currentThread().getName()+"线程启动");}).start();
list.forEach(System.out::println);
2.Stream函数式操作流元素集合
使用Stream API对集合数据进行操作,就类似于使用sql执行的数据库查询。也可以使用Stream API来并行执行操作。
- (1)创建流的方式
/**实体对象的集合,可以用Stream.of和Arrays.stream方法实现*/
Integer[] integers = {1,2,3,4};
Stream<Integer> integers1 = Stream.of(integers);
integers1.forEach(System.out::println);
System.out.println("---------------------");
Stream<Integer> stream = Arrays.stream(integers);
stream.forEach(System.out::println);
System.out.println("---------------------");
/** 自身就是Collection集合的,可以直接通过自身的stream方法,如:Set,List,SortedSet 等 */
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
stream = list.stream();
stream.forEach(System.out::println);
System.out.println("---------------------");
Map map = new HashMap();
map.put("1","1");
map.put("2","2");
map.put("3","3");
map.put("4","4");
Set set = map.entrySet();
Stream stream1 = set.stream();
stream1.forEach(System.out::println);
System.out.println("---------------------");
/** Stream的静态generate方法,创建无限流--不加limit会出现无限循环*/
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.limit(10).forEach(d -> System.out.println(d));
- (2)中间操作
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",19));
userList.add(new User("王五",18));
userList.add(new User("王麻子",20));
userList.add(new User("张三",18));
/** 筛选与切片 */
//filter-过滤年龄大于18岁的用户
userList.stream().filter(user -> user.getAge() > 18).forEach(System.out::println);
System.out.println("---------------------");
//limit-截断流 按倒序排列获取最近两个
userList.stream().sorted(((o1, o2) -> o2.getAge()-o1.getAge())).limit(2).forEach(System.out::println);
System.out.println("---------------------");
//skip-跳过元素
userList.stream().skip(2).forEach(System.out::println);
System.out.println("---------------------");
//distinct--去重--需要重写hashcode和equals方法
userList.stream().distinct().forEach(System.out::println);
System.out.println("---------------------");
/** 映射 */
//map——将元素转换成其他形式或提取信息---提取user中的年龄去重然后转为list集合
List<Integer> collect = userList.stream().map(user -> user.getAge()).distinct().collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("---------------------");
//flatMap-把子元素中的流合并为一个全新的流,也就是扁平化处理
List<List<User>> listList = new ArrayList<>();
listList.add(userList);
listList.add(userList);
Stream<User> userStream = listList.stream().flatMap(users -> users.stream());
userStream.forEach(System.out::println);
- (3)终端操作
//anyMatch——对姓名年龄等进行匹配,检查是否至少匹配一个元素
boolean flg = userList.stream().anyMatch(user -> user.getName().indexOf("张") >= 0);
System.out.println(flg);
System.out.println("---------------------");
//max--返回结果中最大值的数据
Optional<User> max = userList.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max.get());
System.out.println("---------------------");
//归约reduce--计算年纪总数
Optional<Integer> reduce = userList.stream().map(user -> user.getAge()).reduce((user, user2) -> user + user2);
System.out.println(reduce.get());
System.out.println("---------------------");
//collect() 将流转换成其他形式
//求出大于18岁用户的集合
List<User> collect = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("---------------------");
//每个用户统计了多少次
Map<User, Long> collect1 = userList.stream().collect(Collectors.groupingBy(user -> user, Collectors.counting()));
collect1.entrySet().forEach(System.out::println);
System.out.println("---------------------");
//查询集合中是否有重复的值
List<Map.Entry<User, Long>> collect2 = collect1.entrySet().stream().filter(userLongEntry -> userLongEntry.getValue() > 1).collect(Collectors.toList());
collect2.forEach(System.out::println);
- (4)实战
//A学生有好友 B,C。
//B学生有好友A,C,D,E,F
//C学生有好友 A,B,D,F
//求找出A学生的 可能认识的人(不是A同学的朋友,但是与A同学有2或以上个相同的好友)
Student studentA = new Student("A", new String[]{"B", "C"});
Student studentB = new Student("B", new String[]{"A", "C", "D", "E", "F"});
Student studentC = new Student("C", new String[]{"A", "B", "D", "F"});
List<Student> students = new ArrayList<>();
students.add(studentA);
students.add(studentB);
students.add(studentC);
//1、获取当前A同学的朋友["B","C"]
Stream<String[]> a = students.stream().filter(student -> student.getName().equals("A")).map(student -> student.getFriend());
List<String[]> collect = a.collect(Collectors.toList());
Stream<String> stringStream = collect.stream().flatMap(strings -> Stream.of(strings));
List<String> friendA = stringStream.collect(Collectors.toList());
//2、获取A同学朋友的朋友["A","C","D","E","F"],["A","B","D","F"]
Stream<Student> studentStream = students.stream().filter(student -> friendA.stream().anyMatch(s -> s.equals(student.getName())));
Stream<String[]> stream = studentStream.map(student -> student.getFriend());
List<String[]> collect1 = stream.collect(Collectors.toList());
//3、将上述集合铺平["A","C","D","E","F","A","B","D","F"]
Stream<String> stringStream1 = collect1.stream().flatMap(strings -> Stream.of(strings));
List<String> collect2 = stringStream1.collect(Collectors.toList());
//4、剔除A自身和A的朋友["D","E","F","D","F"]
Stream<String> a1 = collect2.stream().filter(s -> !(s.equals("A") || friendA.stream().anyMatch(s1 -> s1.equals(s))));
List<String> collect3 = a1.collect(Collectors.toList());
System.out.println(collect3);
//5、计算重复的值及重复的次数
Map<String, Long> collect4 = collect3.stream().collect(Collectors.groupingBy(o -> o, Collectors.counting()));
System.out.println(collect4);
3.接口新增:默认方法与静态方法
函数式接口(注解:@FunctionalInterface),可以通过Lambda表达式来创建该接口的对象。
它只包含一个自定义的抽象方法的接口, 还可以是Object类的equals抽象方法,还可以default、static修饰的自带方法体,如果实现多个相同default方法的接口,则default方法必须重写。
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
java.util.function.Consumer<T> | T | void | 对类型为T的对象应用操作,包含方法void accept(T t);【消费型】 |
java.util.function.Supplier<T> | 无 | T | 返回类型为T的对象,包含方法 T get(); 【供给型】 |
java.util.function.Function<T,R> | T | R | 参数类型T,返回类型R,包含方法 R apply(T t); 【函数型】 |
java.util.function.Predicate<T> | T | boolean | 参数类型T,返回类型boolean,包含方法 boolean test(T t); 【断言型】 |
/**
* 接口新增:默认方法与静态方法
* default 接口默认实现方法是为了让集合类默认实现这些函数式处理,而不用修改现有代码
* (List继承于Iterable<T>,接口默认方法不必须实现default forEach方法)
*/
@Test
public void testDefaultFunctionInterface(){
//可以直接使用接口名.静态方法来访问接口中的静态方法
JDK8Interface1.staticMethod();
//接口中的默认方法必须通过它的实现类来调用
new JDK8InterfaceImpl1().defaultMethod();
//多实现类,默认方法重名时必须复写
new JDK8InterfaceImpl2().defaultMethod();
}
//@FunctionalInterface
public interface JDK8Interface1 {
//1.接口中可以定义静态方法了
public static void staticMethod(){
System.out.println("接口中的静态方法");
}
//2.使用default之后就可以定义普通方法的方法体了
public default void defaultMethod(){
System.out.println("接口中的默认方法");
}
// public abstract void add();
}
public interface JDK8Interface2 {
//接口中可以定义静态方法了
public static void staticMethod(){
System.out.println("接口中的静态方法");
}
//使用default之后就可以定义普通方法的方法体了
public default void defaultMethod(){
System.out.println("接口中的默认方法");
}
}
public class JDK8InterfaceImpl1 implements JDK8Interface1 {
//实现接口后,因为默认方法不是抽象方法,重写/不重写都成!
// @Override
// public void defaultMethod(){
// System.out.println("接口中的默认方法");
// }
}
public class JDK8InterfaceImpl2 implements JDK8Interface1,JDK8Interface2 {
//实现接口后,默认方法名相同,必须复写默认方法
@Override
public void defaultMethod() {
//接口的
JDK8Interface1.super.defaultMethod();
System.out.println("实现类复写重名默认方法!!!!");
}
}
4.方法引用,与Lambda表达式联合使用
其实是lambda的简写,中间函数式接口只起到上下文作用,可直接省去,直接写函数式接口的具体实现,使用方法引用的方式
public void testMethodReference(){
//构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数;
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
//静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;
cars.forEach( Car::collide );
//任意对象的方法引用。它的语法是Class::method。无参,所有元素调用;
cars.forEach( Car::repair );
//特定对象的方法引用,它的语法是instance::method。有参,在某个对象上调用方法,将列表元素作为参数传入;
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
}
public static class Car {
public static Car create( final Supplier< Car > supplier ) {
System.out.println("构造函数被初始化");
return supplier.get();
}
public static void collide( final Car car ) {
System.out.println( "静态方法引用 " + car.toString() );
}
public void repair() {
System.out.println( "任意对象的方法引用 " + this.toString() );
}
public void follow( final Car car ) {
System.out.println( "特定对象的方法引用 " + car.toString() );
}
}
5.引入重复注解
允许在同一申明类型(类,属性,或方法)前多次使用同一个类型注解。
@Filters({@Filter( value="filter1",value2="111" ),@Filter( value="filter2", value2="222")})
--写法改为了-->
@Filter( value="filter1",value2="111" )
@Filter( value="filter2", value2="222")
6.类型注解
ElementType 枚举增加了TYPE_PARAMETER、TYPE_USE两个枚举值,从而可以使用 @Target(ElementType_TYPE_USE) 修饰注解定义,这种注解被称为类型注解,可以用在任何使用到类型的地方。
TYPE_PARAMETER:表示该注解能写在类型参数的声明语句中。 类型参数声明如: <T>、<T extends Person>
TYPE_USE:表示注解可以再任何用到类型的地方使用,比如允许在如下位置使用:
a.创建对象(用 new 关键字创建)
b.类型转换
c.使用 implements 实现接口
d.使用 throws 声明抛出异常
7.最新的Date/Time API (JSR 310)
//1.Clock
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );//2020-12-24T07:32:56.132Z
System.out.println( clock.millis() );//1608795176247
//2. ISO-8601格式且无时区信息的日期部分
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );
System.out.println( date );//2020-12-24
System.out.println( dateFromClock );//2020-12-24
// ISO-8601格式且无时区信息的时间部分
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );
System.out.println( time );//15:32:56.257
System.out.println( timeFromClock );//15:32:56.257
// 3.ISO-8601格式无时区信息的日期与时间
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
System.out.println( datetime );//2020-12-24T15:32:56.257
System.out.println( datetimeFromClock );//2020-12-24T15:32:56.257
// 4.特定时区的日期/时间,
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );
System.out.println( zonedDatetime );//2020-12-24T15:32:56.258+08:00[Asia/Shanghai]
System.out.println( zonedDatetimeFromClock );//2020-12-24T07:32:56.258Z
System.out.println( zonedDatetimeFromZone );2020-12-23T23:32:56.260-08:00[America/Los_Angeles]
//5.在秒与纳秒级别上的一段时间
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );
final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );//365
System.out.println( "Duration in hours: " + duration.toHours() );//8783
8.新增base64加解密API
final String text = "就是要测试加解密!!abjdkhdkuasu!!@@@@";
String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
System.out.println("加密后="+ encoded );
final String decoded = new String(Base64.getDecoder().decode( encoded ),StandardCharsets.UTF_8 );
System.out.println( "解密后="+decoded );
9.数组并行(parallel)操作
long[] arrayOfLong = new long [ 20000 ];
//1.给数组随机赋值
Arrays.parallelSetAll( arrayOfLong,
index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
//2.打印出前10个元素
Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
i -> System.out.print( i + " " ) );
System.out.println();
//3.数组排序
Arrays.parallelSort( arrayOfLong );
//4.打印排序后的前10个元素
Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
i -> System.out.print( i + " " ) );
System.out.println();
10.JVM的PermGen方法区被移除:取代它的是Metaspace(JEP 122)元空间
-XX:MetaspaceSize初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整
-XX:MaxMetaspaceSize最大空间,默认是没有限制
-XX:MinMetaspaceFreeRatio在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
相关文章链接:
<<<Java基础-反射机制
<<<Java基础-字节码技术
<<<Java基础-创建对象的方式汇总
<<<Java基础-对象布局
<<<Java基础-对象的引用类型
<<<Class文件分析一个类为啥最多支持65535个接口
<<<为什么重写equals还要重写hashcode方法
<<<如何自定义注解
<<<十大经典排序算法汇总-动画演示