tostringbuilder,Java中有哪些不错的IDE值得推荐?
已经有很多答主回答得很全面了,我来往纵向深入说一说不同IDE体验的差别吧。
和其他答主一样,首推IntelliJ IDEA,包括其他的Python、前端开发、PHP、Go等等都推荐使用JetBrains全家桶,这么多人都在推荐,肯定是有道理的。IntelliJ是收费的,推荐有能力的去购买服务。如果是学生的话则可以使用公开的授权服务器(https://www.imsxm.com/)或者自己搭建授权服务器,或者使用EDU邮箱获取一年免费激活码(http://www.bewindoweb.com/169.html)。
三款IDE对比这里主要对比三款经典IDE:Eclipse、MyEclipse、IDEA。
(1)官网对比
看看官网的审美差别吧,你就能大概知道这些软件背后的UI也会是什么类型:
Eclipse:开源软件典型界面,简单、单调,不花钱。(https://www.eclipse.org/downloads/)
MyEclipse:还活在上个世纪,丑到了一定境界,老一辈最喜欢的深蓝庄重颜色。(https://www.genuitec.com/products/myeclipse/)
IDEA:90后,优秀的配色,独特的UI交互。(https://www.jetbrains.com/idea/)
当然它以前的logo也是很丑的(如下图),这是后来设计师重新设计的,但至少人家努力了。
(2)使用对比
相信所有人最开始学JAVA都是老师推荐的Eclipse,因为开源免费。Eclipse确实功能强大,而且有很多插件,但是操作并不人性化。界面也很丑陋。Eclipse的独特之处在于,你想要什么功能,都可以自己去找插件,它都能支持,自己去配置就行。一项一项配置下来,程序还没开动,人先累崩了。不同的插件还有不同的交互方式、一些特殊的处理,你都需要铭记在心,一不小心点到个不同的view(比如切换到了Hadoop的开发界面),你就不知道怎么点回去了,要查半天资料。
然后时代变化,开始学JAVA WEB,最开始用JSP+Servlet,后来用Struts+Spring+Hibernate来搭建Web工程,就开始使用MyEclipse了,因为它有Java Web一些独特的东西,比如自动根据类的属性生成Get/Set方法,不用手动一个一个去写,当时觉得好高级呀。然而界面一样地丑。
再后来偶然接触到JetBrains全家桶,只要你用一次,你就会想用亿次。
说说它的好处吧:
完全无需担心点错
这就是IDEA人性化的地方,它知道你的想法。
比如在接口的左侧有个按钮,画了一个向下的箭头,哪怕你第一次使用,你也八九不离十能够猜到点击它可以看到有哪些类实现了这个接口。
比如右上角有一系列启动按钮,哪怕你第一次使用,你也知道哪个是开始,哪个是DEBUG,哪个是停止,应该点哪里去配置启动参数。
比如你意外地双击类的名字把整个编辑界面全屏了,左侧的project树形结构没有了,一般的IDE都会让你重新选择【视图】→【Project】来把左侧的窗口找回来,IDEA知道你想什么,你想再双击一次让它恢复对不对!是的,再双击就恢复了。
还有很多细节,几乎0成本上手。
强大的生态支持
你想用Maven 3,它支持,而且还能编辑POM文件的时候自动去更新;
你想用Lombok,它支持,只需要简单装一个插件,就可以一个注解替代Get/Set/构造方法/日志/ToString/HashCode的冗余代码编写;
你想用Docker,它支持,能够自动识别Dockerfile;
你想写YML,它支持,还能帮你排除严格的语法错误;
你想用Git,它支持,还能帮你图形化地切换分支;
你想用Spring全家桶,它支持,还能帮你扫描哪些类没有写Component注解
你想用SSH自动同步代码到云上去,它支持,还能选择每次Ctrl+S保存一次就同步一次。
不管你想用什么最新的技术,它都支持,甚至能够帮你把关系型数据库的关联用图画出来。
就算你想用IDEA写Lua程序,它都能搞定……
强大的基础功能IDEA还有JetBrains提供的全家桶基础功能。
比如你修改一个类的名字,它会自动帮你扫描哪些类用到了这个名字,让你选择是否需要一起都改了。
比如你要找某条语句,直接Ctrl+Shift+F在整个项目查找,不用每个页面去翻,哪怕写在注释里也能找到。
比如你新New了一个List,它会自动补全你想要命名为XXXXList,还是XXXXs,还是什么,供你选择,如果没有特殊需求,你一个回车就能完成这条语句的编写了。
你按住Ctrl,就能翻看每个类的具体实现。
你选到了依赖库的代码,它会提示你不应该修改依赖库的代码,防止你错误地修改了库。
你可以在上面编写JAVA DOC的注解,它会自动解析编写的类并上色,如果你JAVA DOC编写的参数和具体的方法参数不对应,还会提示你有语法问题:
如果你写了太多重复语句,它会提示你是否应该写成一个方法来调用。
还能够支持查看Test的覆盖率。
自动补全好用到你颅内高潮,想站起来给它鼓掌……
你还可以自定义注释,在编写的时候自动生成一些注释。
这些功能是全家桶都支持的,只要用熟一个,其他的都会用了,交互逻辑一致。
好看的界面
这些都不说了,都能看出来。
IDEA的配色网上一抓一大把(http://www.riaway.com/theme.php?page=3)
如果你觉得太麻烦,喜欢我的配色的话(我是参考之前用VS的习惯配置的颜色,比如字符串和数字用黄色,类型用蓝色,变量用白色,其余关键字统一绿色,为了区别方法调用和方法定义,定义的时候用的紫色),关注我后私信“IDEA配色”,就会得到我的IDEA配色方案下载地址。
总结不管怎样,不要说什么自己觉得好用的才是最好的,IDEA就是JAVA最好的IDE,没有之一。IDEA做的就是我们一直想做的事情,比如我们总是想这个功能不好用,那个界面不好看,只是一直在吐槽,却没有人动手去做一个又好用又好看的IDE,这一切JetBrains帮我们做了,把其他所有IDE的缺点都改掉了,提供了所有想要的功能,你能吐槽IDEA的点少之又少。
至于C到底用Visual Studio还是用JetBrains系列,倒是要好好考虑下了~
stringbuffer与stringbuilder的区别?
区别1、StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,2、只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
3、在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低
如何去除所有EditText中用setSpan?
可以监听输入事件,然后判断内容,用 SpannableStringBuilder 实现文本高亮
String类型性别sex?
StringBuilder 或者 StringBuffer
你经历过哪些有意思的面试题目?
一、String 原理,String 、StringBuffer、StringBuilder区别。
String是final类,属于不可变字符串,采用char数组。
StringBuffer是线程安全的,内部采用synchronized。
StringBuilder是非线程安全的。
二、String与StringBuilder拼接字符串哪个性能好,为什么?
StringBuilder性能比较好,String在拼接的时候会new出多个对象,消耗资源。尤其是在for循环下进行拼接性能差距很明显。
三、接口与抽象类的区别
1. 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),抽象类可以有非抽象的方法
2. 接口中的实例变量默认是 final 类型的,而抽象类中则不一定
3. 一个类可以实现多个接口,但最多只能实现一个抽象类
4. 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
5. 接口不能用 new 实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
四、重载与重写的区别
重载(Overload)是让类以统一的方式处理不同类型数据的一种手段,实质表现就是多个具有不同的参数个数或者类型的同名函数(返回值类型可随意,不能以返回类型作为重载函数的区分标准)同时存在于同一个类中,是一个类中多态性的一种表现(调用方法时通过传递不同参数个数和参数类型来决定具体使用哪个方法的多态性)。
重写(Override)是父类与子类之间的多态性,实质是对父类的函数进行重新定义,如果在子类中定义某方法与其父类有相同的名称和参数则该方法被重写,不过子类函数的访问修饰权限不能小于父类的;若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法,如需父类中原有的方法则可使用 super 关键字。
五、数组与链表的区别
1.数组是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。最大的特点就是支持随机访问,但插入、删除操作也因此变得比较低效,平均情况时间复杂度为O(n)。
2.链表它并不需要一块连续的内存空间,它通过“指针”(前后节点指向)将一组零散的内存,空间可扩容,比较常用的是单链表,双链表和循环链表。和数组相比,链表更适合插入、删除操作频繁的场景,查询的时间复杂度较高。
六、介绍一下ArrayList
1、ArrayList底层数据结构是一个数组,数组元素类型为Object,对ArrayList的所有操作都是基于数组。
2、ArrayList不是线程安全的。对ArrayList进行添加元素的操作的时候是分两个步骤进行的,即第一步先在object[size]的位置上存放需要添加的元素;第二步将size的值增加1。由于这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。
如果非要在多线程的环境下使用ArrayList,就需要保证它的线程安全性,通常有两种解决办法:第一,使用synchronized关键字;第二,可以用Collections类中的静态方法synchronizedList();
3、ArrayList默认大小为10
4、ArrayList扩容机制:
第一,在add()方法中调用ensureCapacityInternal(size + 1)方法来确定集合确保添加元素成功的最小集合容量minCapacity的值。参数为size+1,代表的含义是如果集合添加元素成功后,集合中的实际元素个数。换句话说,集合为了确保添加元素成功,那么集合的最小容量minCapacity应该是size+1。在ensureCapacityInternal方法中,首先判断elementData是否为默认的空数组,如果是,minCapacity为minCapacity与集合默认容量大小中的较大值。
第二,调用ensureExplicitCapacity(minCapacity)方法来确定集合为了确保添加元素成功是否需要对现有的元素数组进行扩容。首先将结构性修改计数器加一;然后判断minCapacity与当前元素数组的长度的大小,如果minCapacity比当前元素数组的长度的大小大的时候需要扩容,进入第三阶段。
第三,如果需要对现有的元素数组进行扩容,则调用grow(minCapacity)方法,参数minCapacity表示集合为了确保添加元素成功的最小容量。在扩容的时候,首先将原元素数组的长度增大1.5倍(oldCapacity + (oldCapacity >> 1)),然后对扩容后的容量与minCapacity进行比较:① 新容量小于minCapacity,则将新容量设为minCapacity;②新容量大于minCapacity,则指定新容量。最后将旧数组拷贝到扩容后的新数组中。
七、ArrayList在遍历的时候可以删除数据吗?
for循环遍历不可以,会报ConcurrentModificationException异常,迭代器Iterator下可以。
内部有一个modCount 进行修改次数检查。
如果没checkForComodification去检查expectedModCount与modCount相等,这个程序肯定会报ArrayIndexOutOfBoundsException
八、LinkedList底层数据结构是什么?说明ArrayList,LinkedList二者区别?
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构每个元素都包含了 上一个和下一个元素的引用,所以add/remove 只会影响到上一个和下一个元素,。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
九、简单介绍一下HashMap?
1、负载因子0.75 , 提高空间利用率和 减少查询成本的折中,主要是泊松分布,0.75的话碰撞最小。
2、扰动函数就是解决碰撞问题,减少碰撞。
3、hasMap的容量尽量是2的倍数,这样使散列均匀,不易出现hash冲突
HashMap默认初始化大小16,数据结构是一个数组+链表+红黑树(平衡二叉树红黑节点)。
Put的时候首先拿到hash值看是否存在值如果没有值直接放入,存在则进行比较是否相等,不等生成链表,当链表大于8的时候生成红黑树。
HashMap是线程不安全的。
十、介绍一下ConcurrentHashMap
concurrentHashMap是一个线程安全的高可用HashMap。
1.8抛弃了之前的segement分段上锁,采用了CAS+synchronized来保证并发安全,并且吧put的流程更加细化,而且resize的时候不会阻塞任何一个线程。
重要参数:
MIN_TRANSFER_STRIDE: 意思是resize时候每个线程每次最小的搬运量(搬运多少个entry),范围会继续细分以便可以允许多个resize线程。
RESIZE_STAMP_BITS :位的个数来用来生成戳,用在sizeCtrl里面;
MAX_RESIZERS:最大参与resize的线程数量;
RESIZE_STAMP_SHIFT:用来记录在sizeCtrl中size戳的位偏移数。
Put主逻辑:
1、首先判断key\value都不能为null
2、进行自旋操作,每次把当前的table赋给tab
3、计算key的hash
4、如果当前table没有初始化,现代用initTable方法将tab初始化。
5、Tab索引i的位置元素为null,则直接使用CAS插入
6、判断是否在resize(扩容),在扩容走helpTransfer - transfer
7、没有resize走正常put
8、用synchronized针对单个节点加锁
9、判断节点hash(正常node大于0,树为-2)
10、正常节点插入,插入到队尾
11、树节点插入
initTable方法
1、自旋操作每次针对tab赋值而且判断长度
2、如果抢锁失败(sizeCtl作为自旋锁使用),则告诉cpu让出时间片(Thread.yield())
3、抢锁成功,再次检测tab的赋值以及数组长度
4、SizeCtl置为n的0.75
5、finally里面逻辑,sizeCtl赋值并解锁
addCount方法
增加表容量的计数,如果这个表需要resize但还没开始resize,则初始化transfer(这个东西用来进行resize)。如果已经开始resize了,则看看需不需要加入帮助一起resize。然后重新检查表的计数看看需不需要再次resize
transfer方法(resize用此方法):
原理就是让每一个put完的线程,或者想要put的线程到了整个表需要resize的时候都过来进入resize流水线工作,直到有一个线程说自己已经全部弄完了,方法才能返回。
以前的正常设计是resize的时候整个表就阻塞住了,但是现在resize的时候,想要操作的线程都会来参与一起resize,这么一来其他的线程就不用干等着了。
参考文档:https://www.cnblogs.com/kobebyrant/p/11296309.html
自旋锁:
自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
十一、比较各种集合
HashMap与TreeMap:
1、都是非线程安全
2、HashMap通过hashCode进行快速查找,无序;treeMap有序。
3、hashMap基于哈希实现,treeMap基于红黑树实现
4、hashMap适用于Map的插入删除和定位元素,treeMap适用于顺序遍历key
5、HashMap比TreeMap快一点,建议使用hashMap,需要排序的时候再用treeMap。
HashSet与ArrayList:
1.HashSet
1) HashSet不能够存储相同的元素,元素是否相同的判断:重写元素的equals方法。equals方法和hashCode方法必须兼容,如:equals方法判断的是用户的名字name,那么hashCode的返回的hashcode必须是name。hashcode();
2) HashSet存储是无序的,保存的顺序与添加的顺序是不一致的,它不是线性结构,而是散列结构,(通过散列表:散列单元指向链表)。因此,HashSet的查询效率相对比较高。
3) HashSet不是线程安全的,不是线程同步的。这需要自己实现线程同步:Collections.synchronizedCollection(),方法实现。
4) Haset底层用了HashMap用key做的HashSet的value,迭代器循环代码:map.keySet().iterator()
2.ArrayList
1) ArrayList中存放顺序和添加顺序是一致的。并且可重复元素。
2) 不是线程安全的,不是线程同步的。
3) ArrayList是通过可变大小的数组实现的,允许null在内的所有元素。
4) ArrayList适合通过位子来读取元素。
还没有评论,来说两句吧...