语言和封装那些事

网上经常看到有人说,java/c#啰嗦,python/php简洁。那这个现象到底是怎么造成的呢?下面我举一些例子来说明。

场景一:读文件C:\windows\system.ini并在控制台打印出来

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

public class test1 {

	public static void main(String[] args) throws Exception {
		try (FileInputStream is = new FileInputStream("C:\\windows\\system.ini")) {
			byte[] buffer = new byte[8192];
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			while (true) {
				int nread = is.read(buffer);
				if (nread > 0) {
					os.write(buffer, 0, nread);
				} else {
					break;
				}
			}
			String ini = new String(os.toByteArray(), "GBK");
			System.out.println(ini);
		}
	}

}
print(open("C:\\windows\\system.ini").read())

可以看出python版本确实简洁到没边了,我服!但是大家仔细想一想,这是语言注定的吗?

答案是no!no!no!

假设我做了一个java的标准库,在common包里,叫FileKit

package common;

public class FileKit {
	
}

然后我实现两个函数之后

public static byte[] read(InputStream is) throws IOException {
	byte[] buffer = new byte[8192];
	ByteArrayOutputStream os = new ByteArrayOutputStream();
	while (true) {
		int nread = is.read(buffer);
		if (nread > 0) {
			os.write(buffer, 0, nread);
		} else {
			break;
		}
	}
	return os.toByteArray();
}

public static String read(String path, String encoding) throws FileNotFoundException, IOException {
	try (FileInputStream is = new FileInputStream(path)) {
		return new String(read(is), encoding);
	}
}

再来实现这个需求

package example;

import common.FileKit;

public class test2 {
	public static void main(String[] args) throws Exception {
		System.out.println(FileKit.read("C:\\windows\\system.ini", "GBK"));
	}
}

漂亮!只有一行就解决了,至于package、class、main什么的请忽略,这个对于实际项目来说,只占了相当少的成分。

总结一:一门语言的生产力分两个部分,语言语法和库,java很多时候实现起来啰嗦是因为标准库没有提供很多足够高层的常用功能,导致一些功能实现起来需要过多编码。但是只要注意收集好相关的封装即可,特别是对于大项目,管理好自己的基础库,后面的基本都是业务层面的开发了。并不会比动态语言多太多代码。

场景二:从OSC抓取当前最新的众包项目

package example;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.HttpsURLConnection;

public class test3 {

	public static void main(String[] args) throws Exception {
		Pattern pattern = Pattern.compile("href=\"https://zb\\.oschina\\.net/project/.*?>(.*?)</a>",
				Pattern.DOTALL | Pattern.UNICODE_CASE);
		HttpsURLConnection cnx = (HttpsURLConnection) new URL("https://www.oschina.net").openConnection();
		cnx.setRequestProperty("User-Agent", "My Browser");
		cnx.connect();
		try (InputStream is = cnx.getInputStream()) {
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			byte[] buffer = new byte[8192];
			while (true) {
				int nread = is.read(buffer);
				if (nread > 0) {
					os.write(buffer, 0, nread);
				} else {
					break;
				}
			}
			Matcher m = pattern.matcher(new String(os.toByteArray(), "UTF8"));
			while (m.find()) {
				System.out.println(m.group(1));
			}
		}
	}

}
import urllib2, re

pattern = re.compile(r'href="https://zb\.oschina\.net/project/.*?>(.*?)</a>', re.S|re.U)

headers = {"User-Agent" : "My Browser"}
page = urllib2.urlopen(urllib2.Request("https://www.oschina.net", headers=headers)).read().decode("utf8")
for zb in pattern.findall(page): print zb

我的天啊(脑补小岳岳表情),python又以简洁胜出了!!!但是,这并非java命中注定的。

我在common的package下,又加了一个WebKit(怎么那么耳熟?)

package common;

public class WebKit {

}

然后实现一些必要的函数

private static Proxy proxy = null;

public static void setProxy(String ip, int port) {
	proxy = new Proxy(Type.HTTP, new InetSocketAddress(ip, port));
}

public static Proxy getProxy() {
	return proxy;
}

public static byte[] request(String method, String url, byte[] data, boolean gziped, String... headers)
		throws IOException {
	URL u = new URL(url);
	HttpURLConnection cnx;
	if (proxy == null) {
		cnx = (HttpURLConnection) u.openConnection();
	} else {
		cnx = (HttpURLConnection) u.openConnection(proxy);
	}
	cnx.setRequestMethod(method);
	for (int i = 0; i < headers.length; i += 2) {
		cnx.setRequestProperty(headers[i], headers[i + 1]);
	}
	if (gziped) {
		String ce = cnx.getRequestProperty("Accept-Encoding");
		ce = ce == null ? "gzip" : ce + " " + "gzip";
		cnx.setRequestProperty("Accept-Encoding", ce);
	}
	if (data != null && data.length > 0) {
		cnx.setDoOutput(true);
	}
	cnx.setDoInput(true);
	cnx.connect();
	if (cnx.getDoOutput()) {
		try (OutputStream os = cnx.getOutputStream()) {
			os.write(data);
		}
	}
	if (cnx.getDoInput()) {
		try (InputStream is = cnx.getInputStream()) {
			if (gziped && cnx.getHeaderField("Content-Encoding").equals("gzip")) {
				try (GZIPInputStream gis = new GZIPInputStream(is)) {
					return FileKit.read(gis);
				}
			} else {
				return FileKit.read(is);
			}
		}
	} else {
		return new byte[0];
	}
}

public static byte[] get(String url, String... headers) throws IOException {
	return request("GET", url, null, true, headers);
}

然后基于此再实现一次

package example;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import common.WebKit;

public class test4 {
	public static void main(String[] args) throws Exception {
		Pattern pattern = Pattern.compile("href=\"https://zb\\.oschina\\.net/project/.*?>(.*?)</a>",
				Pattern.DOTALL | Pattern.UNICODE_CASE);
		String page = new String(WebKit.get("https://www.oschina.net", "User-Agent", "My Browser"), "UTF8");
		Matcher m = pattern.matcher(page);
		while (m.find()) {
			System.out.println(m.group(1));
		}
	}
}

6行代码打完收工(JFinal体),又一次证明java啰嗦不是语言本身设计得不好,而是库没有提供足够高层次的封装。

场景三:这次我们回到数据结构上来,玩玩Json,大家都知道Json是java的弱项,而且要完整实现篇幅太大,所以关于Json的封装我就提供一个Interface示义。

这次我们先上Python代码作为标杆

import json

data = {
	"a" : [
		{"b": "hello"},
		{"c": "world"}
	]
}
j = json.dumps(data, indent=4)
print j
j1 = json.loads(j)
print j1["a"][1]["c"]

然后上一下Java版的大餐让大家先品品

package example;

import common.JArray;
import common.JMap;
import common.JObject;

public class test5 {

	public static void main(String[] args) {
		JObject data = JMap.build(
				"a", JArray.build(
					JMap.build("b", "hello"), 
					JMap.build("c", "world")
				)
			);
		String j = data.toJson();
		System.out.println(j);
		JObject j1 = JObject.parse(j);
		System.out.println(j1.get("a", 1, "c").toString());
	}

}

也非常简单,那么这样的API是怎样设计的呢?(因为篇幅原因,不放实现了,至少3000行代码)

做一个JObject基类能把很多常用功能接口都暴露出来,不需要整天类型转换

package common;

public abstract class JObject {

	public abstract String toJson();

	public static JObject auto(Object o) {
		return null;
	}
	
	public static JObject parse(String json){
		return null;
	}

	public int toInt() {
		throw new UnsupportedOperationException();
	}

	public String toString() {
		throw new UnsupportedOperationException();
	}

	public double toDouble() {
		throw new UnsupportedOperationException();
	}

	public JMap toMap() {
		throw new UnsupportedOperationException();
	}

	public JArray toArray() {
		throw new UnsupportedOperationException();
	}

	public void add(Object o) {
		throw new UnsupportedOperationException();
	}

	public void put(Object k, Object v) {
		throw new UnsupportedOperationException();
	}
	
	public JObject get(Object k) {
		throw new UnsupportedOperationException();
	}

	//比如{"a":{"b":{"c":1}}},就可以jmap.get("a", "b", "c")
	public JObject get(Object... k) {
		throw new UnsupportedOperationException();
	}
}

JMap和JArray只要实现必须实现的函数即可,其它的由于Java的继承功能,如果用户错误调用了,会自动抛出异常

package common;

public class JMap extends JObject {

	public static JMap build(Object... kvs) {
		return null;
	}

	@Override
	public String toJson() {
		return null;
	}

	@Override
	public JObject get(Object... k) {
		return null;
	}
}
package common;

public class JArray extends JObject {

	public static JArray build(Object... values) {
		return null;
	}

	@Override
	public String toJson() {
		return null;
	}

	@Override
	public JObject get(Object... k) {
		return null;
	}

}

案例就到这里吧,如果你有什么好玩的案例,可以在留言给我,如果能够在短篇幅内描述清楚,我会酌情考虑加入这个帖子。

最后总结一下,为什么Java是比Python好的语言,但是Java做起事情来不一定有Python溜。就是因为Java官方未提供很多高层次的封装方便使用,我觉得这种行为就叫不亲民。包括很多Java框架没考虑最亲民的设计,只想做大而全,结果导致很多同道误以为Java超级啰嗦。

在比较大型的项目开发中,Java/C#等静态语言,确实会比Python/PHP等动态语言具有更好的可控性。但是由于Java并未提供太多亲民的封装,导致除非是比较大型项目的团队或者一些特殊场景的程序,现阶段的第一选择(如Web),并非是Java。

转载于:https://my.oschina.net/visualgui823/blog/829168

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值