`
raymond.chen
  • 浏览: 1418677 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java8新特性

    博客分类:
  • Java
 
阅读更多

1、Lambda表达式

        语法由参数列表、箭头符号 -> 和函数体组成。函数体既可以是一个表达式,也可以是一个代码块。

               (parameters) -> expression 或者 (parameters) -> { statements; }

 

        表达式后面是没有分号的,如果只有一个参数,那么包围参数的圆括号可以省略。

        任何可以接受一个FI实例的地方,都可以用Lambda表达式。

 

        lambda语法

               1、一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数

               2、一个箭头符号:->

               3、方法体,可以是表达式和代码块。

 

2、函数式接口

        函数式接口(Functional Interface)是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

        Java8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查。

        函数式接口可以被隐式转换为 lambda 表达式。

 

        函数式接口里允许定义默认方法。

        函数式接口里允许定义静态方法。

        Object 类的public同名方法不算抽象方法。

 

        内置函数式接口:

             Function              一元函数:                                Function<T, R>                     R apply(T t);

             BiFunction           二元函数:                                BiFunction<T, U, R>              R apply(T t, U u);

            UnaryOperator     一元算子:输入输出同类型       UnaryOperator<T>                T apply(T t);

            BinaryOperator     二元算子:输入输出同类型       BinaryOperator<T>               T apply(T t, T t);

            Predicate              一元断言:返回boolean          Predicate<T>                      boolean test(T t);

            BiPredicate           二元断言:返回boolean          BiPredicate<T, U>               boolean test(T t, U u);

            Consumer            一元消费者:无返回值              Consumer<T>                   void accept(T t);

            BiConsumer         二元消费者:无返回值              BiConsumer<T, U>            void accept(T t, U u);

            Supplier               供应者:无参,只有返回值       Supplier<T>                      T get();

 

        如定义了一个函数式接口如下:

@FunctionalInterface
interface GreetingService{
	//抽象方法
	void sayMessage(String message);
	
	//默认方法:只需在方法名前面加个default关键字即可。
	default void doWork1(){
		//Method body
	}
	
	//静态方法
	static void printHello(){
		System.out.println("Hello");
	}
}

       那么就可以使用Lambda表达式来表示该接口的一个实现(JAVA8之前一般是用匿名类实现的):

              GreetingService greetService1 = message -> System.out.println("Hello " + message);

 

3、方法引用

       语法: 

              左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名

 

        一般方法的引用格式

               如果是静态方法,则是ClassName::methodName

               如果是实例方法,则是Instance::methodName

               如果是构造函数,则是ClassName::new

               超类上的实例方法:super::methodName

               数组构造方法:TypeName[]::new

 

 4、Stream 串行流

       Stream(流)是一个来自数据源的元素队列并支持聚合操作

/**
 * Stream:
 * 		findFirst:取集合第一个元素
 * 		min:取集合的最小值
 * 		max:取集合的最大值
 * 		forEach:集合循环处理
 *		forEachOrdered:严格顺序循环处理
 * 		filter:过滤
 * 		sorted:排序,n1-n2大于升序,n2-n1大于降序
 * 		map:值转换处理
 * 		mapToXXX:值转成XXX型
 * 		flatMap:将一个2维的集合转成1维度
 * 		collect:集合归并处理
 * 		allMatch:所有元素都满足条件才返回true
 * 		anyMatch:任一元素满足条件则返回true
 * 		noneMatch:无一元素满足条件才返回true
 * 		reduce:a[0]与a[1]进行二合运算,结果与a[2]做二合运算,以此类推。求和、求最大、最小值等
 *		reducing:
 * 		distinct:去掉重复值
 *		peek:对每个元素执行操作并返回一个新的 Stream
 * 		limit:限制最大数量
 *		skip:忽略指定个数
 *              parallel:转成并行流
 */
 private static void testStream(){
	Integer value;
	List<Integer> numbers = Arrays.asList(29, 19, 5, 11, 7, 13, 11, 3, 13, 2);
	List<String> list3 = Arrays.asList("k1|v1", "k2|v3", "k3|v3", "k4|v4", "k5|v5");

	//取第一个元素
	value = numbers.stream().findFirst().get();

	//取集合的最小值、最大值
	value = numbers.stream().min((m, n) -> m-n).get();
	value = numbers.stream().min(Integer::min).get();
	
	value = numbers.stream().max((m, n) -> m-n).get();
	value = numbers.stream().max(Integer::max).get();

	//forEach
	numbers.stream().forEach(n -> System.out.print(String.valueOf(n) + ", "));
 
    //生成0-100的随机数,取10个,升序排序
    new Random().ints(0, 100).limit(10).sorted().forEach(System.out::println);

	//forEachOrdered
	numbers.stream().forEachOrdered(n -> System.out.print(String.valueOf(n) + ", "));

	//filter 过滤出大于5的数值,sorted 升序排序,map 各元素值减1,collect 数值归并成一个List集合
	List<Integer> list = numbers.stream().filter(n -> n>5)
			.sorted((n1, n2) -> n1-n2).map(n -> n-1).collect(Collectors.toList());

	//多个过滤条件
	Predicate<Integer> p1 = (n) -> n>12;
	Predicate<Integer> p2 = (n) -> n<20;
	List<Integer> list2 = numbers.stream().filter(p1.and(p2)).collect(Collectors.toList());

	//mapToInt:转成IntStream
	//summaryStatistics:取得个数、最小值、最大值、总和以及平均值
	IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
	System.out.println("count: " + stats.getCount());
	System.out.println("min: " + stats.getMin());
	System.out.println("max: " + stats.getMax());
	System.out.println("sum: " + stats.getSum());
	System.out.println("average: " + stats.getAverage());

	//求和: rangeClosed 生成某个范围的数值
	value = IntStream.rangeClosed(1, 10).boxed().mapToInt(Integer::intValue).sum();
	
	//flatMap:将一个2维的集合转成1维度
	list3.stream().flatMap(item -> Arrays.stream(item.split("\\|"))).collect(Collectors.toList()).forEach(System.out::print);

	//xxxMatch 元素条件判断
	boolean b = numbers.stream().allMatch(n -> n>19); //所有元素都满足条件才返回true
	b = numbers.stream().anyMatch(n -> n>0); //任一元素满足条件则返回true
	b = numbers.stream().noneMatch(n -> n>30); //无一元素满足条件才返回true
	
	//reduce做求和处理
	value = numbers.stream().reduce((sum, x) -> sum + x).get();
	value = numbers.stream().reduce(0, Integer::sum);  //sum的初始值为0

	//reducing: sum的初始值为0,每个元素值+1,最后求和
	value = Arrays.asList(1, 3, 5).stream().collect(Collectors.reducing(0, x -> x+1, (sum, n) -> sum+n));

	//distinct 去掉重复值
	List<Integer> list1 = numbers.stream().distinct().collect(Collectors.toList());

	//map:数值转换处理,对列表的每个元素应用函数  String.valueOf(x-1)
	//distinct:去重,joining:用分号连接各元素为一个字符串
	String value2 = numbers.stream().map((x) -> String.valueOf(x-1))
			.distinct().collect(Collectors.joining(";"));

	//peek:对每个元素执行操作并返回一个新的 Stream
	//limit:限制返回的个数
	//skip:忽略指定个数
	List<String> list5 = Stream.of("11", "one", "two", "three", "four")
			 .filter(e -> e.length() > 2)
			 .peek(e -> System.out.println("Filtered value: " + e))
			 .map(String::toUpperCase)
			 .peek(e -> System.out.println("Mapped value: " + e))
			 .limit(3)
			 .skip(2)
			 .collect(Collectors.toList());
 }

 

    //排序: Comparator类的用法

//普通排序
List<Integer> numbers = Arrays.asList(29, 5, 13, 3, 18, 2);
//numbers.stream().sorted().forEach(s -> System.out.print(s + "  "));
//numbers.stream().sorted(Comparator.naturalOrder()).forEach(s -> System.out.print(s + "  ")); //自然顺序
numbers.stream().sorted(Comparator.reverseOrder()).forEach(s -> System.out.print(s + "  ")); //降序


List<Person> list = new ArrayList<>();
list.add(new Person("name6", 29));
list.add(new Person("name5", 19));
list.add(new Person("name1", 29));
list.add(new Person("name3", 22));
list.add(new Person("name4", 19));
list.add(new Person("name2", 22));

//先按age升序,然后反转变为降序
list.stream()
	.sorted(Comparator.comparing(Person::getAge).reversed())
	.forEach(System.out::println);

//按age降序
list.stream()
	.sorted(Comparator.comparing(Person::getAge, Comparator.reverseOrder()))
	.forEach(System.out::println);

//多字段排序:先按age降序,然后按name升序
list.stream()
	.sorted(Comparator.comparing(Person::getAge, Comparator.reverseOrder()).thenComparing(Person::getName))
	.forEach(System.out::println);

 

5、parallelStream 并行流

       paralleStream里直接修改变量是非线程安全的,但是采用collect和reduce操作可以满足线程安全。

       parallelStream只是做到别浪费cpu,cpu负载大不要用。

       不要在多线程中使用parallelStream。

       请确保每条处理无状态且没有关联。

       N可用的数据量 x Q对每个元素执行的计算量 > 10000 就会获得有效提升

list.parallelStream().sorted((n1, n2) -> n1-n2).collect(Collectors.toList());

//通过加锁保证parallel并行处理是线程安全的
Lock lock = new ReentrantLock();
IntStream.range(0, 10000).parallel().forEach(i -> {
	lock.lock();
	try {
		list.add(i);
	}finally {
		lock.unlock();
	}
});

 

6、Collectors

/**
 * Collectors:收集器
 * 		toList:汇集为List
 * 		toSet:汇集为Set
 * 		toMap:汇集为Map
 * 		toCollection:转换成特定的集合
 * 		joining:连接成字符串
 * 		averagingInt:求平均值
 * 		minBy:求最小值
 * 		maxBy:求最大值
 * 		summingInt:求和
 * 		summarizingXXX:可以获取最大值、最小值、平均值、总和值、总数
 * 		mapping: 先对集合中的元素进行映射,然后再对映射的结果使用Collectors操作
 * 		groupingBy:分组汇集,返回Map
 * 		groupingByConcurrent:分组汇集,返回ConcurrentMap
 * 		mapping: 先对集合中的元素进行映射,然后再对映射的结果使用Collectors操作
 * 		partitioningBy:用于分成两组的情况,一组true,一组false
 * 		reducing:累计处理
 */
private static void testCollectors(){
	Integer value;
	List<Integer> numbers = Arrays.asList(29, 19, 5, 11, 7, 13, 11, 3, 13, 2);
	List<String> list3 = Arrays.asList("k1|v1", "k2|v2", "k3|v3", "k4|v4", "k5|v5");

	//toList
	List<Integer> list = numbers.stream().filter(n -> n>10).collect(Collectors.toList());
	
	//toSet
	Set<Integer> set = numbers.stream().filter(n -> n>10).collect(Collectors.toSet());
	
	//toMap
	Map<String, String> map3 = numbers.stream().collect(Collectors.toSet()).stream().collect(Collectors.toMap(k -> "key"+k, v -> "value"+v));
	map3.forEach((k,v) -> {
		System.out.println(k + "=" + v);
	});
	
	//toCollection:转换成特定的集合
	TreeSet<Integer> treeSet = numbers.stream().collect(Collectors.toCollection(TreeSet::new));
	
	//joining:连接成一个字符串
	String result = list3.stream().collect(Collectors.joining(", ")); 
	
	//averagingInt 计算平均值
	Double average = numbers.stream().collect(Collectors.averagingInt(n -> n));

	//最小值 minBy
	value = numbers.stream().collect(Collectors.minBy((x, y) -> x - y)).get();

	//最大值 maxBy
	value = numbers.stream().collect(Collectors.maxBy((x, y) -> x - y)).get();
	
	//求和 summingInt
	value = numbers.stream().collect(Collectors.summingInt(n -> n));
	
	//summarizingInt
	IntSummaryStatistics stat = numbers.stream().collect(Collectors.summarizingInt(n -> n));
	System.out.println(stat.getCount());
	System.out.println(stat.getMin());
	System.out.println(stat.getMax());
	System.out.println(stat.getSum());
	System.out.println(stat.getAverage());
	
	//mapping: 先对集合中的元素进行映射,然后再对映射的结果使用Collectors操作
	String value3 = numbers.stream().collect(Collectors.mapping(n -> String.valueOf(n+10), Collectors.joining(",")));
	
	//分组
	Map<Integer, List<Integer>> map1 = numbers.stream().collect(Collectors.groupingBy(n -> n)); //数据分组
	
	//分组汇集,返回ConcurrentMap
	ConcurrentMap<Integer, List<Integer>> map2 = numbers.stream().collect(Collectors.groupingByConcurrent(n -> n));
	
	//数据分组,对每组的值计算count
	Map<Integer, Long> map = numbers.stream().collect(Collectors.groupingBy(n -> n, Collectors.counting()));
	
	//partitioningBy 用于分成两组的情况,一组true,一组false
	Map<Boolean, List<Integer>> map4 = numbers.stream().collect(Collectors.partitioningBy(n -> n%2==0));
	
	//reducing: sum的初始值为0,每个元素值+1,最后求和  
	value = Arrays.asList(1, 3, 5).stream().collect(Collectors.reducing(0, x -> x+1, (sum, n) -> sum+n));
}

 

7、Optional

     Optional是Java8提供的为了解决null安全问题的一个API。Optional仅仅是一个容器:存放T类型的值或者null。

//value is null
Address addr = null;
String city = Optional.ofNullable(addr).map(a -> a.getCity()).orElseGet(() -> "none");
System.out.println(city);

//值存在则isPresent()方法会返回true
System.out.println(Optional.empty().isPresent());
System.out.println(Optional.of(100).isPresent());

//value is not null
addr = new Address("province", "city");
city = Optional.ofNullable(addr).map(a -> a.getCity()).orElse("Unknown");
System.out.println(city);

//value is null,throw exception
User user = null;
try{
	city = Optional.ofNullable(user)
		.map(u -> u.getAddress())
		.map(a -> a.getCity())
		.orElseThrow(() -> new IllegalArgumentException("The value of param user isn't available"));
}catch(Exception ex){
	ex.printStackTrace();
}

//filter
user = new User(1L, "uid", "pwd", addr);
Optional<User> optional = Optional.ofNullable(user)
	.filter(u -> u.getId() == 1);
if(optional.isPresent()){
	System.out.println(optional.get().getUsername());
}

 

8、用ScriptEngine动态执行JS

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine engine = scriptEngineManager.getEngineByName("nashorn");


//js value
Integer result = (Integer) engine.eval("10 + 2");
System.out.println(result);

engine.eval("var username='cjm'; password='123'; var array=['A','B','C']; var json={uid:'cjm', age:40};");
System.out.println(engine.get("username"));

ScriptObjectMirror array = (ScriptObjectMirror)engine.get("array");
System.out.println(array.getSlot(1));

ScriptObjectMirror json = (ScriptObjectMirror) engine.get("json");
System.out.println(json.get("uid"));

engine.put("age", 35);
engine.eval("var age = age - 5");
System.out.println(engine.get("age"));

//js Object
engine.eval("var obj=new Object(); obj.info='object info'; obj.getInfo=function(){return this.info;}; ");

ScriptObjectMirror obj = (ScriptObjectMirror) engine.get("obj");
System.out.println(obj.get("info"));
System.out.println(obj.get("getInfo"));
System.out.println(engine.eval("obj.getInfo()"));

//将变量导入js脚本
Map<String, Object> input = new TreeMap<>();
input.put("a", 3);
input.put("b", 4);
System.out.println(engine.eval("Math.pow(a,b)", new SimpleBindings(input)));

//调用js函数
engine.eval("function add (a, b) {return a+b;}");
Invocable jsInvoke = (Invocable) engine;
Object value = jsInvoke.invokeFunction("add", new Object[] {10, 5});
System.out.println(value);

 

9、Base64

//Encoder
String value = Base64.getEncoder().encodeToString("username:用户名".getBytes("utf-8"));
System.out.println(value);

byte[] bytes = Base64.getDecoder().decode(value);
System.out.println(new String(bytes, "utf-8"));

//UrlEncoder
value = Base64.getUrlEncoder().encodeToString("http://www.baidu.com?uid=张三&pwd=123".getBytes("utf-8"));
System.out.println(value);

bytes = Base64.getUrlDecoder().decode(value);
System.out.println(new String(bytes, "utf-8"));

//MimeEncoder
StringBuilder sb = new StringBuilder();
for (int i=0; i<10; i++) {
	sb.append(UUID.randomUUID().toString());
}
byte[] mimeBytes = sb.toString().getBytes("utf-8");
value = Base64.getMimeEncoder().encodeToString(mimeBytes);
System.out.println(value);

bytes = Base64.getMimeDecoder().decode(value);
System.out.println(new String(bytes, "utf-8"));

 

10、并行数组

long[] arr = new long [10];

//生成随机数,放到一个数组里
Arrays.parallelSetAll(arr, x -> ThreadLocalRandom.current().nextInt(100));
Arrays.stream(arr).limit(10).forEach(i -> System.out.print(i + " "));
System.out.println();

//数组并行排序
Arrays.parallelSort(arr);
System.out.println();

 

11、日期时间处理

      jdk8新增一个新的日期时间处理包java.time,该包中的类是不可变且线程安全的。主要的类包括:LocalDate、LocalTime、LocalDateTime、ZonedDateTime、时钟Clock、时间戳Instant、时段Period等。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics