E se não houvesse null no java

26 respostas
peczenyj

Ola.

Em Ruby, null é um objeto (da classe NilClass). Em Perl eu tenho um estado “indefinido” (undef). Em C eu tenho uma macro NULL que pode ser 0x00.

Fiquei aqui pensando então: e se java não suportasse referencias nulas?

Será que teria alguma vantagem (além de evitar NullPointerException)?
Será que o Garbage Collector teria que funcionar de uma forma totalmente diferente?

26 Respostas

Marky.Vasconcelos

Hmm… acho que teriamos que ter um “objeto vazio”, não sei como ficaria.

foxpv

Não sei como o Ruby ou o Perl tratam isso (ainda estou só começando a estudar Ruby). Mas, será que isso não poderia difilcultar na manutenção n? Já que poderia encobertar, alguns erros de objeto não inicializado?

Marky.Vasconcelos

Bem, acho que se não existisse null, nós teriamos que inventar isso.

Provavelmente algum convention para tratar objetos não inicializados.

É dificil imaginar também antigamente na matematica quando o sinal de igual não existia.

fredferrao

Em Scala temos a classe Option, porque tudo é um objeto, então até o retorno vazio deve ser tratado como tal, o Alex cita o cara que criou o null em seu livro Programming Scala:


“Tony Hoare, who invented the null reference in 1965 while working on an objectoriented
language called ALGOL W, called its invention his ?billion dollar mistake?
(see [Hoare2009]). Don?t contribute to that figure.”

Antes desta citação ele começa com esta esplanação:


Most languages have a special keyword or object that?s assigned to reference variables
when there?s nothing else for them to refer to. In Java, this is null; in Ruby, it?s nil. In
Java, null is a keyword, not an object, and thus it?s illegal to call any methods on it.
But this is a confusing choice on the language designer?s part. Why return a keyword
when the programmer expects an object?

Leozin

Poisé, até no próprio livro de PEAA eles falam sobre null object

Acho que null é mais uma das desvatangens da linguagem em sí, tal como checked exceptions.

Giulliano

Em Ruby o null é uma classe, em Java é apenas uma indicação de que o objeto não possue rerferência na memória. Mas na prática:

Se fizermos um IF em um objeto nulo o Ruby nos retorna falso. Por que para ser verdadeiro é necessátrio ser true e somente true. Logo qualquer coisa diferente de true é false. inclusive null ou nil como é chamado em Ruby.

Porém se tentarnos invocar um método num objeto nulo a exceção ocorre do mesmo jeito.

kicolobo

Se não me engano, no Objective-C não há NULL no sentido “Javaniano”, e há coletores de lixo

(eu odeio null)

J

kicolobo:
Se não me engano, no Objective-C não há NULL no sentido “Javaniano”, e há coletores de lixo

(eu odeio null)

Olá kiko. No objective c existe o nil semelhante ao nosso object-pascal.
O NULL/null/nil/etc… somente trata um ponteiro sem “apontador” digamos. A medida que o nível das linguagens sobe, os profissionais vão criando algumas maneiras de lidar com ela de modo mais prático, conhecidos como smartpointers, até chegar no que conhecemos como coletores de lixo. Essas referências nulas sempre vão existir, não há como programar sem elas, já que precisamos alocar e desalocar recursos em uma área de memória(mesmo que alguns frameworks façam isso por nós).

Smart Pointers são uma leitura na minha opinião muito interessante. Usando c ou c++, inclusive pascal se pode chegar a coletores lixo.

kicolobo

juliocbq:
kicolobo:
Se não me engano, no Objective-C não há NULL no sentido “Javaniano”, e há coletores de lixo

(eu odeio null)

Olá kiko. No objective c existe o nil semelhante ao nosso object-pascal.
O NULL/null/nil/etc… somente trata um ponteiro sem “apontador” digamos. A medida que o nível das linguagens sobe, os profissionais vão criando algumas maneiras de lidar com ela de modo mais prático, conhecidos como smartpointers, até chegar no que conhecemos como coletores de lixo. Essas referências nulas sempre vão existir, não há como programar sem elas, já que precisamos alocar e desalocar recursos em uma área de memória(mesmo que alguns frameworks façam isso por nós).

Smart Pointers são uma leitura na minha opinião muito interessante. Usando c ou c++, inclusive pascal se pode chegar a coletores lixo.
http://en.wikipedia.org/wiki/Smart_pointer

Boa Julio!

Há algum tempo atrás dei uma lida por alto sobre Objective-C, e me lembro que fiquei meio perdido com isto.

fredferrao

juliocbq:
kicolobo:
Se não me engano, no Objective-C não há NULL no sentido “Javaniano”, e há coletores de lixo

(eu odeio null)

Olá kiko. No objective c existe o nil semelhante ao nosso object-pascal.
O NULL/null/nil/etc… somente trata um ponteiro sem “apontador” digamos. A medida que o nível das linguagens sobe, os profissionais vão criando algumas maneiras de lidar com ela de modo mais prático, conhecidos como smartpointers, até chegar no que conhecemos como coletores de lixo. Essas referências nulas sempre vão existir, não há como programar sem elas, já que precisamos alocar e desalocar recursos em uma área de memória(mesmo que alguns frameworks façam isso por nós).

Smart Pointers são uma leitura na minha opinião muito interessante. Usando c ou c++, inclusive pascal se pode chegar a coletores lixo.
http://en.wikipedia.org/wiki/Smart_pointer

Como assim não da? Talvez não de para o criador da linguagem, mas como ja citado o null como existe no Java(uma keyword) é tratado diferente em outras linguagens, como ja citado o Ruby e o Scala, onde temos um Objeto de fato para lidar com isto.

Vamos a um exemplo:

val umMap = Map(
  "chave1" -> "valor1",
  "chave2" -> "valor2")

  println(umMap.get("chave1"))
  
  println(umMap.get("teste"))

O resultado dos println:

Some(valor1)
None

Ou seja dois objetos, e este objetos tem metodos e tudo mais, em java o segundo println nos retornaria um null, em scala ele nos retornou um None, uma subclasse de Option, que foi desenhada para evitar nulos na lingagem, imagina se este get estivesse dentro de algum processamento e fossemos usa-lo para algo ja teriamos um NullPointerException na cara.

Agora olha que legal, no caso acima pegamos as Options, se quisermos o objetos de fato, fariamos assim.

println(umMap.get("chave1").get)
>valor1

//agora aqui sim teriamos uma exception pois None não possui valor.
println(umMap.get("teste").get)
//erro: NoSuchElementException

//Mas a classe Option possui metodos para evitar isto, fariamos assim para ficarmos seguros de nao receber uma exception
println(umMap.get("teste").getOrElse("alguma coisa se nao existir"))
>alguma coisa se nao existir


Scala encourages you to use the
Option type for variables and function return values when they may or may not refer to
a value. When there is no value, use None, an object that is a subclass of Option. When
there is a value, use Some, which wraps the value. Some is also a subclass of Option.

Ou seja se eu seguir este estilo de “vida” estarei programando sem o nulos como os os de java, estarei trabalhando apenas com Objetos.
E toda a linguagem foi desenhada para me retornar um Option caso o valor possa ou não existir, como no exemplo acima. Resumindo, nunca terei um NullPointerException.

J

fredferrao:
Ou seja se eu seguir este estilo de “vida” estarei programando sem o nulos como os os de java, estarei trabalhando apenas com Objetos.
E toda a linguagem foi desenhada para me retornar um Option caso o valor possa ou não existir, como no exemplo acima. Resumindo, nunca terei um NullPointerException.


Não terá, pois essa classe gerencia memória para você. Ela é um “smart pointer”.

Ser você olhar como usuário final de uma ferramenta sim, do ponto de vista computacional não. Alguém ou algo vai gerenciar os ponteiros para você, não há como fugir disso.

Só estou olhando de um ponto de vista mais próximo da máquina. Nas linguagens de alto nível essas tarefas já estão implementadas e organizadas de modo que estejam transparentes ao programador.

peczenyj

O que me motivou a fazer esta pergunta é o fato de Haskell não ter null, porém é uma linguagem funcional.

fredferrao

juliocbq:
fredferrao:
Ou seja se eu seguir este estilo de “vida” estarei programando sem o nulos como os os de java, estarei trabalhando apenas com Objetos.
E toda a linguagem foi desenhada para me retornar um Option caso o valor possa ou não existir, como no exemplo acima. Resumindo, nunca terei um NullPointerException.

Ser você olhar como usuário final de uma ferramenta sim, do ponto de vista computacional não. Alguém ou algo vai gerenciar os ponteiros para você, não há como fugir disso.

Concordo. É que ficou meio generalista tua frase :slight_smile: . Eu como usuario final da linguagem Scala por exemplo estou livre disto vamos dizer. Claro que por baixo dos panos em algum lugar alguem tera que fazer o trabalho sujo.

J

fredferrao:
juliocbq:
fredferrao:
Ou seja se eu seguir este estilo de “vida” estarei programando sem o nulos como os os de java, estarei trabalhando apenas com Objetos.
E toda a linguagem foi desenhada para me retornar um Option caso o valor possa ou não existir, como no exemplo acima. Resumindo, nunca terei um NullPointerException.

Ser você olhar como usuário final de uma ferramenta sim, do ponto de vista computacional não. Alguém ou algo vai gerenciar os ponteiros para você, não há como fugir disso.

Concordo. É que ficou meio generalista tua frase :slight_smile: . Eu como usuario final da linguagem Scala por exemplo estou livre disto vamos dizer. Claro que por baixo dos panos em algum lugar alguem tera que fazer o trabalho sujo.

Sim. Tudo depende do nível da linguagem. Quanto mais distante do assembly, maiores funcionalidades, em contrapartida o desempenho cai um pouco.

Até em c++. Se você usar a classe template auto_ptr, vai conseguir gerenciar memória como um programa java. O desempenho dela não é muito bom mas a boost tem um set de smartpointers muito bons.

J

O esquema do haskell deve ser bem diferente dessas demais. O compilador ou interpretador deve mapear todos os ponteiros resolvendo as referencias nulas e apontando-as para algum tipo de dado não nulo. Difícil de imaginar como mesmo.

B

utlizando esse exemplo, onde cidade está nula:

cliente.getCidade().getEstado();

Como a tipagem é fixa, quando não é utilizada uma referencia de memória, não podemos retornar um tipo diferente do declarado como retornado pelo método, pois dessa forma geraria outra exception como “Type mismatch: cannot convert from NullObject to Cidade”.

E se em vez disparar NullPointerException fosse adotado um NullObject, geraria algo do tipo “The method getEstado() is undefined”.

Só de ver casos como esses da pra ter uma idéia quantos detalhesinhos poderiam complicar a vida do programador.

fredferrao

É que voce foi muito profundo Julio, foi la na heap :lol:

Acho que a pergunta foi, se nao existir na linguagem como existe hoje, como seria o tratamento, como tratariamos isto em nosso código.

Em Scala eu simplesmente nao consigo criar um ponteiro nulo, tipo:
//Em java eu posso fazer isto
Map b;
// pronto ja criei um ponteiro pra lugar nenhum, claro que o compilador vai pedir pra inicia-la se eu usar logo abaixo, mas poderia fazer
Map b = null;  //agora sim, aponta para o limbo

//ja em Scala eu nao consigo fazer isto
val b: Map
//da erro, eu sou obrigado a dar um valor a ele, o mesmo vale pra qualquer tip
val c: Int //novamente erro
val d: Int = 1 //agora sim
//ou melhor
val e = 1 //com type inference

Ou seja(ainda to começando com scala, posso por ventura falar alguma asneira :shock: ), teoricamente eu nunca terei um ponteiro apontando pra null.

J
fredferrao:
É que voce foi muito profundo Julio, foi la na heap :lol:

Acho que a pergunta foi, se nao existir na linguagem como existe hoje, como seria o tratamento, como tratariamos isto em nosso código.

Em Scala eu simplesmente nao consigo criar um ponteiro nulo, tipo:
//Em java eu posso fazer isto
Map b;
// pronto ja criei um ponteiro pra lugar nenhum, claro que o compilador vai pedir pra inicia-la se eu usar logo abaixo, mas poderia fazer
Map b = null;  //agora sim, aponta para o limbo

//ja em Scala eu nao consigo fazer isto
val b: Map
//da erro, eu sou obrigado a dar um valor a ele, o mesmo vale pra qualquer tip
val c: Int //novamente erro
val d: Int = 1 //agora sim
//ou melhor
val e = 1 //com type inference

Ou seja(ainda to começando com scala, posso por ventura falar alguma asneira :shock: ), teoricamente eu nunca terei um ponteiro apontando pra null.

Ahh sim, eu não estava levando em conta esse paradoxo. Desculpem.

Andre_Brito

Não? Eu achei que tinha… Em Scala existem tantos nulls (Nothing , Null null, Nil… até o Náim fazem daqui a pouco :p) que é fácil de se perder.

ViniGodoy

É quase como trabalhar com garbage collection em C++. Quem quiser conhecer, tem uma série de artigos sobre eles no Ponto V!:
http://www.pontov.com.br/site/index.php/cpp/43-smart-pointers

ViniGodoy

Acho que o importante da ausência de null, seria realmente a ausência total do conceito de nulidade.
Ou seja, não adianta ter um objeto que representa o null. Por que aí, o conceito ainda está presente e você fatidicamente ainda terá uma nullpointerexception. Muda-se a os chifres e as manchas, mas o boi continua o mesmo.

Como eliminariamos esse conceito? Em algumas funções que retornam listas, já fazemos isso através da lista vazia (que representa o conjunto vazio). Alguns outros objetos também tem valores que representam a ausência (o vetor (0,0) e a matriz identidade, na matemática, a String “”, etc). O interesse do “objeto nulo” é quando ele pode ser usado como um objeto não nulo. É possível fazer for…each numa lista vazia sem obter erro, ou somar um vetor (0,0) com um outro vetor, sem que haja problemas.

Seria possível eliminar isso para os demais métodos ou criar isso para as demais classes? Bem, em métodos que aceitam um parâmetro opcional, certamente poderíamos ter duas assinaturas, uma com um objeto, outra sem. Métodos que retornam um objeto só poderiam retornar listas, e usar-se do conjunto vazio. Em alguns tipos de classes, é possível criar um objeto estático representado o valor vazio (como o “” da String).

Agora, será que isso deixaria os sistemas mais simples? Não sei se com as linguagens atuais. Talvez se implementarmos algum tipo de suporte melhor a conjuntos, isso até poderia ser feito. Coisa que é feita em linguagens funcionais, e daí o sumiço do null no Haskel.

lina

Oi,

o NUllPointerException mostra que sua programação esta “furada”. Logo, acho importante ter essa Exceção.

Tchauzin!

L

Usar null não é muito diferente de falar palavrão: é possível evitar, mas você está tão acostumado que o usa do mesmo jeito.

O problema principal é que a maioria dos programadores não entendem de máquinas de estado. Talvez porque morcegaram na aula de Linguagens Formais e Autômatos, ou talvez porque nunca tiveram essa disciplina na faculdade. Por não conhecer, usam null como estado da aplicação. Exemplo: uma classe Pedido possui dataEntrega como atributo que, quando for nulo, significa que o pedido ainda não foi entregue. Ou seja, ao invés de evitar o null, torna-o como parte fundamental para o funcionamento do sistema. E olha que existem outras opções, como criar um enum ou usar o pattern State.

Ponteiro null não tem nada de baixo nível, Assembly não tem referências; é apenas uma maneira pobre de pensar sobre uma linguagem.

Haskell e Scala tem opções quanto ao ponteiro null, é basicamente um container que armazena um valor ou nenhum valor. Mas não é só isso, Haskell tem a notação “do” e Scala tem for-compreensions. Ao colocar uma sequência de instruções dentro de um “do”/for-compreension, se uma delas retornar Nothing, as instruções seguintes param de ser executadas e Nothing é retornado no final. É um jeito mais simples do que verificar com ifs cada retorno de programa.

A

Leonardo3001:
Usar null não é muito diferente de falar palavrão: é possível evitar, mas você está tão acostumado que o usa do mesmo jeito.

Vocês costumam utilizar aquele pattern de NullObject?

Ou ao criar uma enum incluir um valor como INDEFINIDO ?

Procuro fazer isso em aplicações pessoais mas não vejo esse tipo de ténica muito difundida por aí.

fredferrao

Não? Eu achei que tinha… Em Scala existem tantos nulls (Nothing , Null null, Nil… até o Náim fazem daqui a pouco :p) que é fácil de se perder.

Scala tem null, apenas por retrocompatibilidade com .NET e Java, mas seu uso é totalmente desencorajado!

Nil é uma lista vazia. um empty List

J
Leonardo3001:
Usar null não é muito diferente de falar palavrão: é possível evitar, mas você está tão acostumado que o usa do mesmo jeito.

...

Ponteiro null não tem nada de baixo nível, Assembly não tem referências; é apenas uma maneira pobre de pensar sobre uma linguagem.

...

Ponteiros são o que há de mais próximo da máquina. Uma maneira de enxergar um bloco de memória. Toda linguagem de programação usa isso, independente no nível, mesmo que seja transparente. Assembly endereça memória da mesma maneira.

Isso aqui é um exemplo simples de ponteiro e endereçamento.

//EAX foi carregado com um endereço de um local que guarda um byte. Temos uma variavel double pointer e queremos armazenar esse endereço dentro dela.
MOV [pointer],EAX
//pointer agora possui o endereço de EAX, mas queremos carregar o conteúdo da área que pointer aponta. No registrador CH.

MOV EBX,[pointer]
MOV CH,[EBX]

http://www.friedspace.com/assembly/intro.php

Não entendo porque é uma maneira pobre de pensar em uma linguagem. Se for analizar (sistemicamente), não há como evitá-los e eles sempre estarão presentes(a cpu funciona assim).

Criado 2 de setembro de 2010
Ultima resposta 3 de set. de 2010
Respostas 26
Participantes 14