从Java和JavaScript来学习Haskell和Groovy(汇总)

programming language

这是这个系列的最后一篇,从编程范型的角度概览,前面几篇的链接在文章后半部分有汇总。

我在之前已经介绍过编程范型的概念,而事实上,我们到现在为止,纠结在这四门迥异的语言上面,浅看是各种语言特性,深看就是编程范型和思维方法。

下面这张“神图”来自于这里,可以说是对于范型和语言归类的概览,从左往右从更强的声明式向着更弱的声明式发展;依据状态分为Unnamed state(串行或并发,包含逻辑式和函数式这几种分类)、Nondet. state(所谓的不确定性状态)和Named state(包含数据流、消息传递和状态共享这几种分类),Haskell出现在了左侧函数式语言的分支内,而Java出现在了右侧

[……]阅读全文

从Java和JavaScript来学习Haskell和Groovy(DSL)

dsl 这是《从Java和JavaScript来学习Haskell和Groovy》系列的第四篇。

首先来理解DSL。

DSL(Domain Specific Language)指的是一定应用领域内的计算机语言,它可以不强大,它可以只能在一定的领域内生效(和GPL相比,GPL是General Purpose Language),表达仅限于该领域,但是它对于特定领域简洁、清晰,包含针对特定领域的优化。

当我们面对各种各样的特定需求的时候,一个通用的语言往往不能高效地提供解决问题的路径,相应的DSL并不是并非要解决所有的问题,但是它只关注于某一个小领域,以便解决那一个小领域的问题就好了。比如HTML,只用

[……]阅读全文

从Java和JavaScript来学习Haskell和Groovy(元编程)

metaProgramming

本篇文章的话题是元编程。首先来认识元编程,我在第一篇《引子》里面已经介绍:元编程,指的是在运行时改变“类”的定义,例如访问、增加或修改等等。一言以蔽之,就是“用程序来写程序”。在第二篇的《类型系统》里面已经借由继承和接口的实现,介绍了一些利用元编程特性来增加或改变子类行为的方法。回顾语言发展的长河,其实是经历了一个从“对象 -> 类 -> 元类”到“对象 -> 原型”的发展过程的。所以,无论是类,还是元类,这样的概念其实都不是非有不可的,只是因为我们思考的习惯,特别是抽象的习惯而顺其自然地产生了。这一点我在《编程范型:工具的选择》里面已经详细描述了,建议在往下阅读前移步。

[……]阅读全文

从Java和JavaScript来学习Haskell和Groovy(类型系统)

Haskell 接上文《从Java和JavaScript来学习Haskell和Groovy(引子)》

首先搞清几个概念:

  • 动态类型(Dynamic Typing)和静态类型:区别的核心在编译期还是运行时。静态类型的语言系统在编译期就明确知道每一个变量的类型,如果发现不合法的类型赋值就在编译期报错;动态类型则直到运行时才会报错。
  • 类型推导(Type Inference),类型推断是指可以在上下文中,编译器来推导实际的类型,也就是代码使用隐式类型指定。比如一个简简单单的“var a=1”,a就被推断成整型。
  • 弱类型(Weakly Typed)和强类型:指的是语言系统对类型检查,或者是类型之间互相转换

[……]阅读全文

从Java和JavaScript来学习Haskell和Groovy(引子)

compare 我记得刚接触计算机的时候,我就受到了两个非常巨大的错误观念的影响,这个观念最初是来自于老师的传授还是学长的教诲已经记不清了,但是直到我工作几年以后,才慢慢有了实际的体会:

  1. 学习和使用什么编程语言不重要,重要的是算法和设计;
  2. 程序员学习的精髓是面向对象的设计模式,掌握以后,一通百通。

简直就是是胡扯啊。也许在某个极其狭隘的上下文中还能这样说,但是泛泛而谈,这样的态度无疑是误人子弟的。

就说第一条,编程语言不但重要,而且太重要了。换句话说,学习一门新的编程语言,可能学习的是背后的范型和思考问题的方式。如果这个部分能带来新的东西,那就是值得花时间投入的。

可能很多人和我的背景一样,熟悉Java和

[……]阅读全文

Java容器类型复习笔记

data_structures 最近抽空把java.lang下面常用的那些容器类型(数据结构)复习了一下,这些东西是基础,平时使用的时候也可以很容易查得到,有些方法大概知道,但是总是弄混,如果可以记住那些重要方法,并且能够熟练使用的话,还是可以让编码过程变得容易很多。另外一个是实现机制,对于常用数据结构的实现机制,应该说是必须要熟知的。

另外,并发容器我之前整理过,放在这篇文章里。

Queue

  1. add和offer的区别在于达到上限时add抛出异常,offer返回false;
  2. remove和poll的区别在于,队列为空时前者抛出异常,后者返回空;
  3. element和peek都返回队列头部元素,但是前者失败不抛出异常,后者返回

[……]阅读全文

运行时动态增加枚举类型

enum 最近在使用一个内部框架的时候,希望能够在运行时指定枚举类型,却发现这是一件挺麻烦的事情(不找别的替代方式,就是要动态增加enum的类型),方法也不正统,不过作为有趣的尝试,研究研究也无妨,下面的内容主要来自于《Java – create enum instances dynamically》这样一篇文章。在一切开始前,如果你想问,为什么非要增加/改变enum类型?其实这是一个非常好的问题,多数情况下这是应对被避免的,但是这不在今天我的讨论范围内。

一、方法 void addEnum(Class<T> enumType, String enumName),用于增加一个枚举类型:

&n

[……]阅读全文

泛型传递

chain 最近在读代码的过程中,经常遇到一些利用泛型来对调用链中的参数进行类型约束的情形,特指对于调用链中后面环节的参数类型和返回值,由前面环节的参数类型来确定,我草率地把它称作泛型传递(技巧很简单,但是用得好会很有趣;我不知道这个东西正儿八经的名字叫做什么)。

在说这个事情以前,对于Java的泛型,还是和其它语言中有些许的不同,这里需要结合使用方法泛型和类泛型,如有不明,对于其中的使用可以参考这篇《泛型趣谈》,而其实下面要说的内容,其实也就是这篇文章中提到的“链式调用”。另外,也顺便提一句,“泛型”和“范型”可是完全不相干的东西,相差十万八千里(若有混淆,关于“范型”,可以移步阅读这篇文章)。

很多

[……]阅读全文

Java多线程程序的测试

work

这个问题最初来自于一封公司内部的话题探讨邮件,再加上了一些我的理解。

首先,需要明确的是,用Java通常构建多线程安全的程序“非常”困难,如果还没有体会到“非常”的话,阅读《Java Concurrency in Practice》(中文名叫做《Java并发编程实战》,在我的书单里面,我认为它基本是最好的系统介绍Java并发的书了)可能可以改变你的看法。

多线程的基础

基础是王道。对于任何一门语言都是如此,有的基础部分是和语言无关的,也有一部分是和Java语言相关的。这里我不过多展开,但是我想提一提对于JSR规范的理解。通常我们认为Java是一门啰嗦、冗长,容易使用,而且不容易造成破坏的语言

[……]阅读全文

一段集合操作的不同语言表达

看到这样一条微博,觉得挺有意思,就记录在这里:

所谓对比,Java真是足够啰嗦:

weibo

图不清楚,我来再叙述一下。要做的事情就是,把原有列表里面的每个元素都变成大写的,再放到一个新列表里面去。

这是Java7的版本: 

List list = Arrays.asList("andy", "michael", "thomas");
List list2 = new ArrayList<>();
for(String s : list)
	list2.add(s.toUpperCase());

 这是Java8的版本(移步阅读:《Java8集合中的Lambda表达

[……]阅读全文

多重继承的演变

think

本来想告一段落别写编程范型的东西,但是这个话题最近发现很有意思,就拣出来唠一唠。从中除了能看出很多有趣的语言特性,观察不同语言的设计,还可以发现程序语言的发展过程。这里谈到的语言特性,都是从C++的多重继承演变而来的,都没法完整地实现和代替多重继承本身,但是有了改进和变通,大部分功能保留了下来,又避免了多重继承本身的问题。

C++的多重继承

这个问题我觉得需要从老祖宗C++谈起,我记得刚开始学C++的时候老师就反复教育我们,多重继承的问题。比如说二义性问题,也就是说,两个父类如果定义了同名的方法,调用它的时候编译器就不知道怎么办了。

但是需要说清楚的是,多重继承确实是有其使用场景的,

[……]阅读全文

泛型趣谈

strange

Java中的泛型带来了什么好处?规约。就像接口定义一样,可以帮助对于泛型类型和对象的使用上,保证类型的正确性。如果没有泛型的约束,程序员大概需要在代码里面使用大量的类型强制转换语句,而且需要非常清楚没有标注的对象实际类型,这是容易出错的、恼人的。但是话说回来,泛型可不只有规约,还有很多有趣的用法,容我一一道来。

 

泛型擦除

Java的泛型在编译阶段实际上就已经被擦除了(这也是它和C#泛型最本质的区别),也就是说,对于使用泛型的定义,对于编译执行的过程,并没有任何的帮助(有谁能告诉我为什么按着泛型擦除来设计?)。所以,单纯利用泛型的不同来设计接口,会遇到预期之外的问题,比如

[……]阅读全文

Java8集合中的Lambda表达式

lambda

本文翻译自《Java 8 Explained: Applying Lambdas to Java Collections》。

Lambdas表达式是Java 8的主题,在Java平台上我们期待了很久。但是,如果如果我们不在集合中使用它的话,就损失了很大价值。把现有接口迁移成为lambda风格接口的问题已经通过default methods,也就是defender methods解决了。在这篇文章里面我们来看一看Java集合里面的批量数据操作(bulk operation)。

批量操作

最初的变更文档已经说了,批量操作是“给Java集合框架添加的用以批量操作数据的功能,而它是基于lam

[……]阅读全文

Java的日期API真烂

date 记得在我刚学Java的时候,真是搞不清楚Date和Calendar这两个类,后来我渐渐知道,原来不能全怪我啊,Java日期API之烂是公认的(不妨参见这篇文章,Tiago Fernandez做过一个投票,就是要选举最烂的Java API,结果Java日期API排行第二,仅次于臭名远扬的EJB2,嘿嘿)。

蛋疼的java.sql.Date

只有Date和Calendar搞定一切吗?那还好啊。当然不是!光Date就有java.util.Date和java.sql.Date,而且关系是java.sql.Date extends java.util.Date。为了把前者转成后者,我写了这样的代码

[……]阅读全文

C++程序员和Java程序员的差异

C  _Java 首先说明,这几年接触的最多的程序员就是C++程序员和Java程序员,这只是我自己的一点体会而已,一个人的眼光难免是浅薄的。不过,欢迎拍砖,也欢迎对号入座。

从对基础知识掌握的程度来说,例如数据结构和算法,C++程序员要比Java程序员牢靠得多。究其原因,大概是因为C++程序员需要经常自己实现那些项目基础设施,但是Java程序员大多拿来即用。公平地说,C++不是一门适合程序员初学者的语言,但是Java是。C++程序看起来确实要比Java程序稍难懂一些,C++程序员往往思维更加严密。另一方面,我也发现内地的程序员要比沿海和发达城市的程序员基础扎实,而且低调内敛,不那么浮华,但是就是善于解决那些难

[……]阅读全文

Java多线程发展简史

image 这篇文章,大部分内容,是周五我做的一个关于如何进行Java多线程编程的Knowledge Sharing的一个整理,我希望能对Java从第一个版本开始,在多线程编程方面的大事件和发展脉络有一个描述,并且提及一些在多线程编程方面常见的问题。对于Java程序员来说,如果从历史的角度去了解一门语言一个特性的演进,或许能有不同收获。

 

引言

首先问这样一个问题,如果提到Java多线程编程,你会想到什么?

 

  • volatile、synchronized关键字?
  • 竞争和同步?
  • 锁机制?
  • 线程安全问题?
  • 线程池和队列?

好吧,请原谅我在这里卖的关

[……]阅读全文

你真的精通Java吗?

java 简历和自我介绍上经常能够读到“精通Java”这样的话,有人和我说,精通Java的人太多了,精通Java已经不能算亮点、不能给自己加分了。可是事实真是这样吗?

对于语言的学习,我有一种观点,一是纵向,即要选择一门自己认为合适的语言学到有相当的深度。二在于横向,即要学习不同类型、不同历史和不同门派的语言:

  1. 既有底层的语言,也有高级语言;
  2. 接触一些动态语言、函数式语言;
  3. 了解一些不同语言的编程范型和编程方式,比如基于原型编程、面向切面编程、命令式编程等等;
  4. 最好能关注一门年纪尚浅,甚至小众的语言,了解一门语言的发展。

横向类比能够带来对一门语言的

[……]阅读全文

杂记:Java的无锁编程和锁优化

Peterson 算法(Dekker算法的演化),这个算法设计得很巧妙,理解的核心就是搞清楚三个标志位是怎样控制两个方法对临界区的访问的:

volatile int flag1 = 0; //主观因素:flag1表示方法1自身是否要求进入临界区   
volatile int flag2 = 0; //主观因素:flag2表示方法2自身是否要求进入临界区   
volatile int turn = 1; //客观因素:turn取1和2分别表示当前临界区针对方法1还是方法2开放  
  
void fun1(){   
  flag1 = 1;   
  turn = 2;   
  while

[……]阅读全文

back to top