Java8实战-总结3

news2024/11/27 4:18:47

Java8实战-总结3

  • 基础知识
      • 多线程并非易事
    • 默认方法

基础知识

几乎每个Java应用都会制造和处理集合。但集合用起来并不总是那么理想。比方说,从一个列表中筛选金额较高的交易,然后按货币分组。需要写一大堆套路化的代码来实现这个数据处理命令,如下所示:

	//建立累积交易分组的Map
	Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>(); 
	
	//遍历交易的List
	for(Transaction transaction : transactions) {
		//筛选金额
		if(transaction.getPrice() > 1000) {
			//提取交易货币
			Currency currency = transaction.getcurrency();
			List<Transaction> transactionsForCurrency = transactionsByCurrencies.get(currency);
			if(transactionsForCurrency == null) {
				//如果这个货币的分组Map是空的,就建立一个
				transactionsForcurrency = new ArrayList<>();
				transactionsByCurrencies.put(currency, transactionsForCurrency);
			}
			//将当前遍历的交易添加到具有同一货币的交易List中
			transactionsForCurrency.add(transaction);
		}
	}

此外,很难一眼看出来这些代码是做什么的,因为有好几个嵌套的控制流指令。有了Stream API,可以这样解决这个问题了:

import static java.util.stream.Collectors.toList;
Map<Currency, List<Transaction>> transactionsByCurrencies = transactions.stream()
.filter((Transaction t) -> t.getPrice() > 1000)
.collect(groupingBy(Transaction::getcurrency));

值得注意的是,和Collection API相比,Stream API处理数据的方式非常不同。用集合的话,得自己去做迭代的过程。得用for-each循环一个个去迭代元素,然后再处理元素。把这种数据迭代的方法称为外部迭代。相反,有了Stream API,根本用不着操心循环的事情。数据处理完全是在库内部进行的。把这种思想叫作内部迭代。

使用集合的另一个头疼的地方是,想想看,要是交易量非常庞大,要怎么处理这个巨大的列表呢?单个CPU根本搞不定这么大量的数据。一台多核电脑,理想的情况下,可能想让这些CPU内核共同分担处理工作,以缩短处理时间。理论上来说,要是有八个核,那并行起来,处理数据的速度应该是单核的八倍。

多核

所有新的台式和笔记本电脑都是多核的。它们不是仅有一个CPU,而是有四个、八个,甚至更多CPU,通常称为"内核"。问题是,经典的Java程序只能利用其中一个核,
其他核的处理能力都浪费了。类似地,很多公司利用计算集群(用高速网络连接起来的多台计算机)来高效处理海量数据。Java 8提供了新的编程风格,
可更好地利用这样的计算机。

Google的搜索引擎就是一个无法在单台计算机上运行的代码的例子。它要读取互联网上的每个页面并建立索引,将每个互联网网页上出现的每个词都映射到包含该词的网址上。
然后,如果用多个单词进行搜索,软件就可以快速利用索引,返回一个包含这些词的网页集合。想想看,如何在Java中实现这个算法,哪怕是比Google小的引擎也需要利用计算机上所有的核。

多线程并非易事

通过多线程代码来利用并行(使用先前Java版本中的Thread API)并非易事线程可能会同时访问并更新共享变量。因此,如果没有协调好,数据可能会被意外改变。相比一步步执行的顺序模型,这个模型不太好理解。比如,下图就展示了如果没有同步好,两个线程同时向共享变量sum加上一个数时,可能出现的问题。
在这里插入图片描述
Java 8也用Stream API(java.util.stream)解决了这两个问题:集合处理时的套路和晦涩,以及难以利用多核。这样设计的第一个原因是,有许多反复出现的数据处理模式,类似于filterApplesSQL等数据库查询语言里熟悉的操作,如果在库中有这些就会很方便:根据标准筛选数据(比如较重的苹果),提取数据(例如抽取列表中每个苹果的重量字段),或给数据分组(例如,将一个数字列表分组,奇数和偶数分别列表)等。第二个原因是,这类操作常常可以并行化。例如下图所示,在两个CPU上筛选列表,可以让一个CPU处理列表的前一半,第二个CPU处理后一半,这称为分支步骤(1)。CPU随后对各自的半个列表做筛选(2)。最后(3),一个CPU会把两个结果合并起来(Google搜索这么快就与此紧密相关,当然他们用的CPU远远不止两个了)。
在这里插入图片描述

到这里,只是说新的Stream APIJava现有的集合API的行为差不多:它们都能够访问数据项目的序列。不过,现在最好记得,Collection主要是为了存储和访问数据,而Stream则主要用于描述对数据的计算。这里的关键点在于,Stream允许并提倡并行处理一个Stream中的元素。筛选一个Collection(将filterApples应用在一个List上)的最快方法常常是将其转换为Stream,进行并行处理,然后再转换回List,下面举的串行和并行的例子都是如此。利用StreamLambda表达式顺序或并行地从一个列表里筛选比较重的苹果。

顺序处理:

import static java.util.stream.Collectors.toList;
List<Apple> heavyApples = inventory.stream()
							.filter((Apple a)-> a.getWeight() > 150)
							.collect(toList()));

并行处理:

import static java.util.stream.Collectors.toList;
List<Apple> heavyApples = inventory
							.parallelStream()
							.filter((Apple a)-> a.getWeight() > 150)
							.collect(toList ());

在加入所有这些新玩意儿改进Java的时候,Java 8设计者发现的一个现实问题就是现有的接口也在改进。比如,Collections.sort方法真的应该属于List接口,但却从来没有放在后者里。理想的情况下,会希望做list.sort(comparator),而不是Collections.sort(list, comparator)。这看起来无关紧要,但是在Java8之前,可能会更新一个接口,然后发现把所有实现它的类也给更新了——简直是逻辑灾难!这个问题在Java 8里由默认方法解决了。

Java中的并行与无共享可变状态

都说Java里面并行很难,而且和synchronized相关的玩意儿都容易出问题。那Java8里面有什么“灵丹妙药”呢?事实上有两个。首先,库会负责分块,
即把大的流分成几个小的流,以便并行处理。其次,流提供的这个几乎免费的并行,只有在传递给filter之类的库方法的方法不会互动(比方说有可变的共享对象)时才能工作。
但是其实这个限制对于程序员来说挺自然的,举个例子,Apple::isGreenApple就是这样。确实,虽然函数式编程中的函数的主要意思是“把函数作为一等值”,
不过它也常常隐含着第二层意思,即“执行时在元素之间无互动”。

默认方法

Java 8中加入默认方法主要是为了支持库设计师,让他们能够写出更容易改进的接口。这一方法很重要,因为会在接口中遇到越来越多的默认方法,但由于真正需要编写默认方法的程序员相对较少,而且它们只是有助于程序改进,而不是用于编写任何具体的程序,这里举个例子。

下面这段Java 8示例代码:

List<Apple> heavyApples1 = inventory.stream().filter((Apple a)-> a.getWeight() > 150).collect(toList ());

List<Apple> heavyApples2 = inventory.parallelstream().filter((Apple a)-> a.getWeight() > 150).collect(toList());

但这里有个问题:在Java8之前,List<T>并没有streamparallelStream方法,它实现的Collection<T>接口也没有,因为当初还没有想到这些方法。可没有这些方法,这些代码就不能编译。换作自己的接口的话,最简单的解决方案就是让Java8的设计者把stream方法加入Collection接口,并加入ArrayList类的实现。

可要是这样做,对用户来说就是噩梦了。有很多的替代集合框架都用Collection API实现了接口。但给接口加入一个新方法,意味着所有的实体类都必须为其提供一个实现。语言设计者没法控制Collections所有现有的实现,这下就进退两难了:如何改变已发布的接口而不破坏已有的实现呢?
Java 8的解决方法就是打破最后一环——接口如今可以包含实现类没有提供实现的方法签名了!那谁来实现它呢?**缺失的方法主体随接口提供了(因此就有了默认实现),而不是由实现类提供。**这就给接口设计者提供了一个扩充接口的方式,而不会破坏现有的代码。Java 8在接口声明中使用新的default关键字来表示这一点。

例如,在Java8里,现在可以直接对List调用sort方法。它是用Java8 List接口中如下所示的默认方法实现的,它会调用Collections.sort静态方法:

	default void sort(Comparator<? super E> c) {
		Collections.sort(this, c);
	}

这意味着List的任何实体类都不需要显式实现sort,而在以前的Java版本中,除非提供了sort的实现,否则这些实体类在重新编译时都会失败。不过一个类可以实现多个接口,不是吗?那么,如果在好几个接口里有多个默认实现,是否意味着Java中有了某种形式的多重继承?是的,在某种程度上是这样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/764379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cocos creator Richtext点击事件

组件如图 添加ts自定义脚本&#xff0c;定义onClickFunc点击方法&#xff1a; import { Component, _decorator} from "cc";const { ccclass } _decorator; ccclass(RichTextComponent) export class RichTextComponent extends Component{public onClickFunc(even…

reggie优化02-SpringCache

1、SpringCache介绍 2、SpringCache常用注解 package com.itheima.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.itheima.entity.User; import com.itheima.service.UserService; import lombok.extern.slf4j.Slf4j; imp…

Mybatis:传参+提交事务(自动or手动)+sql多表关联查询(两种方法)

目录 一、参数两种类型&#xff1a; 二、传参的几种方法&#xff1a; 三、提交事务 四、sql多表关联查询(两种方法) 一、参数两种类型&#xff1a; 1.#{参数}&#xff1a;预编译方式&#xff0c;更安全&#xff0c;只用于向sql中传值&#xff1b; select * from admin w…

getattr, __getattr__, __getattribute__和__get__区别

一、getattr() 和另外三个方法都是魔法函数不同的是&#xff0c;getattr()是python内置的一个函数&#xff0c;它可以用来获取对象的属性和方法。例子如下: class A():a 5def __init__(self, x):self.x xdef hello(self):return hello funca A(10)print(getattr(a, x)) #…

2023 双非本科三个月互联网找实习心路历程

双非本科三个月互联网找实习心路历程 1、实习面试准备2、面试日历&#xff08;1&#xff09;开发投递&#xff08;2&#xff09;线下宣讲&#xff08;3&#xff09;转投测试&#xff0c;机会多多 3、同窗现状4、货拉拉 offer 的故事5、我的闲言6、我的收获(1&#xff09;勇气&a…

2.5 线性表的建表

1. 顺序表建表 #include <iostream>/// <summary> /// 数组最大长度 /// </summary> const int MAX_SIZE 10;/// <summary> /// 顺序表建表 /// </summary> /// <param name"arr">数组</param> /// <param name"…

万达商管IPO:看似轻舟已过万重山,实则负重前行?

近日&#xff0c;继万达商管债券发行计划被终止、证监会质疑万达商场销售数据真实性、珠海万达商管的股权被法院冻结后又解冻&#xff0c;万达商管又遇“水逆”——惠誉发布报告下调万达商管的评级&#xff0c;并认为珠海万达商管可能无法在2023年底前完成上市。 纷至沓来的负…

什么是链路跟踪 Skywarking

什么是链路跟踪 Skywarking 链路跟踪&#xff08;Link Tracing&#xff09;是一种用于追踪分布式系统中请求路径和性能的技术。SkyWalking 是一个开源的 APM&#xff08;Application Performance Monitoring&#xff09;系统&#xff0c;它提供了链路跟踪功能。 SkyWalking 的…

ceph----应用

文章目录 一、创建 CephFS 文件系统 MDS 接口1.1 服务端操作1.2 客户端操作 二、创建 Ceph 块存储系统 RBD 接口三、OSD 故障模拟与恢复 一、创建 CephFS 文件系统 MDS 接口 1.1 服务端操作 1&#xff09;在管理节点创建 mds 服务 cd /etc/ceph ceph-deploy mds create node0…

Java编程-基本排序算法

冒泡排序 图解 &#xff08;注&#xff1a;图片来源网络&#xff09; Java代码 package suanfa_Ja;import org.apache.hadoop.security.SaslOutputStream;// 基本排序算法&#xff0c;冒泡排序 时间复杂度 O(n^2) 空间复杂度O(1) public class BubbleSort {public static v…

blender 建模马拉松

效果展示 蘑菇模型创建&#xff1a; 创建蘑菇头 shift A &#xff0c;创建立方体&#xff1b; 右下工具栏添加细分修改器&#xff08;视图层级&#xff1a;2&#xff0c;渲染&#xff1a;2&#xff09;&#xff1b;tab键进入编辑模式&#xff0c;alt z 进入透显模式&…

Python项目依赖项管理的秘诀:requirements.txt文件

一、背景 公司里面很多时候我们开发的Python项目都不只是我们一个人使用&#xff0c;而是整体团队使用。Python项目需要在别人的电脑环境中运行&#xff0c;则需要别人的电脑环境中也要安装上我们项目需要的python库。那么项目中到底用到了哪些Python库&#xff0c;每个库具体…

12.matlab数据分析——多项式的建立 (matlab程序)

1.简述 多项式及其建立 在运算中我们经常接触到的就是所谓的多项式&#xff0c;比如很常见的一个多项式&#xff1a; 这里我们就说这是一个x的多项式&#xff0c;最高次是2次&#xff0c;常数项是3&#xff0c;二次项的系数是1&#xff0c;一次项的系数是2&#xff0c;相信这些…

流程管理是什么?“流程管理”到底管什么?

流程管理&#xff08;process management&#xff09;&#xff0c;是一种以规范化的构造端到端的卓越业务流程为中心&#xff0c;以持续的提高组织业务绩效为目的的系统化方法。 任正非曾在一次访谈时说到&#xff1a; “权力要放进流程中&#xff0c;流程才有权力&#xff0c…

【Django学习】(十四)自定义action_router

之前我们的视图类可以继承GenericViewSet或者ModelViewSet&#xff0c;我们不用再自定义通用的action方法&#xff0c;但是有时候我们需要自定义action&#xff0c;我们该如何设计呢&#xff1f; 自定义action 1、手写视图逻辑 1.1、先在视图集里自定义action方法&#xff0…

LeetCode 790. 多米诺和托米诺平铺 - 二维空间的动态规划

多米诺和托米诺平铺 中等 304 相关企业 有两种形状的瓷砖&#xff1a;一种是 2 x 1 的多米诺形&#xff0c;另一种是形如 “L” 的托米诺形。两种形状都可以旋转。 给定整数 n &#xff0c;返回可以平铺 2 x n 的面板的方法的数量。返回对 109 7 取模 的值。 平铺指的是每个…

icp许可证 办理流程(icp资质申请条件)

icp许可证 办理流程(icp资质申请条件)是什么&#xff1f; ICP经营许可证是可以线上无忧办理的&#xff0c;包下证&#xff0c;流程也很简单&#xff0c;只需要你提供企业营业执照、法人身份证这些基础材料就可以。加急10-20工作日拿证&#xff0c;普通20-60工作日拿证。 在了解…

使用Vue的插件clipboard使用复制功能

1.安装clipboard插件 npm install clipboard 2.使用 clipboard <template><div style"margin-right: auto;margin-left: auto; 800px"><el-table :data"list"><el-table-column label"搜索引擎" prop"name"&g…

Python迭代器与生成器

文章目录 迭代器创建迭代器StopIteration 生成器 迭代器 访问集合元素的一种方式&#xff0c;可以记住遍历的位置的对象 从集合的第一个元素开始&#xff0c;直到所有的元素被访问完结束&#xff0c;迭代器只能往前不会后退 iter()&#xff0c;创建迭代器对象 iter(object, …

docker中配置mysql主从分离

目录 前言 1、下载mysql安装包 2、mysql 读写分离 3、docker安装三台mysql服务 4、修改主从配置文件 5、重启mysql 6、配置主库 7、配置从库创建同步账户 7.1、进入MySQL01和MySQL02和mysql03服务器新增MySQL用户user 密码root 用于同步账号和密码&#xff1b; 7.2、验…